目录
- [1. 带头双向循环链表的实现](#1. 带头双向循环链表的实现)
-
- [1.1 引子](#1.1 引子)
- [1.2 带头双向循环链表功能分析](#1.2 带头双向循环链表功能分析)
- [1.3 带头双向循环链表的实现](#1.3 带头双向循环链表的实现)
-
- [1.3.1 双向链表:存储数据的结构体](#1.3.1 双向链表:存储数据的结构体)
- [1.3.2 双向链表:结点创建与链表数据清理](#1.3.2 双向链表:结点创建与链表数据清理)
- [1.3.3 双向链表:数据插入与删除](#1.3.3 双向链表:数据插入与删除)
- [2. 顺序表与链表的区别](#2. 顺序表与链表的区别)
1. 带头双向循环链表的实现
1.1 引子
单链表在实现随机插入与删除上效率低,实现困难。其结构上不够优秀与完美,由此我们引入新的一种更优的链表结构。带头双向循环链表。
1.2 带头双向循环链表功能分析
数据存储方式:
- 零碎的内存空间做结点
数据管理方式:
- 增(头插,尾插,随机插入):push_front,push_back,insert,insertafter
- 删(头删,尾删,随机删除):pop_front,pop_back,erase,eraseafter
- 改(指定数据的修改):modify
- 查(指定数据的查询):find
1.3 带头双向循环链表的实现
链表结构:

1.3.1 双向链表:存储数据的结构体
链表结点的构建:
c
typedef struct ListNode
{
struct ListNode* pre;
struct ListNode* next;
int val;
}ListNode;
1.3.2 双向链表:结点创建与链表数据清理
结点创建:
c
ListNode* BuyNewNode(LTDataType val)
{
ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
if (newnode == NULL)
{
perror("malloc failed");
exit(-1);
}
newnode->val = val;
newnode->next = newnode->pre = NULL;
return newnode;
}
链表创建:
c
ListNode* ListCreate()
{
ListNode* head = BuyNewNode(0);
head->next = head;
head->pre = head;
return head;
}
链表销毁:
c
void ListDestory(ListNode* plist)
{
assert(plist);
ListNode* count = plist->next;
while (count != plist)
{
plist->next = count->next;
count->next->pre = plist;
free(count);
count = plist->next;
}
}
1.3.3 双向链表:数据插入与删除
头插头删:
c
//头插
void ListPushFront(ListNode* plist, LTDataType x)
{
assert(plist);
ListNode* newnode = BuyNewNode(x);
newnode->next = plist->next;
newnode->pre = plist;
newnode->next->pre = newnode;
plist->next = newnode;
}
//头删
void ListPopFront(ListNode* plist)
{
assert(plist);
//不为空
assert(plist->next != plist);
ListNode* cur = plist->next;
plist->next = cur->next;
cur->next->pre = plist;
free(cur);
}
尾插,尾删:
c
void ListPushBack(ListNode* plist, LTDataType x)
{
assert(plist);
ListNode* newnode = BuyNewNode(x);
newnode->next = plist;
newnode->pre = plist->pre;
plist->pre->next = newnode;
plist->pre = newnode;
}
void ListPopBack(ListNode* plist)
{
assert(plist);
//不为空
assert(plist->next != plist);
ListNode* cur = plist->pre;
ListNode* pre = cur->pre;
pre->next = plist;
plist->pre = pre;
free(cur);
}
随机插入,删除
c
//寻找指定结点
ListNode* ListFind(ListNode* plist, LTDataType x)
{
assert(plist);
ListNode* cur = plist->next;
while (cur != plist)
{
if (cur->val == x)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
//pos前插入
void ListInsert(ListNode* pos, LTDataType x)
{
assert(pos);
ListNode* newnode = BuyNewNode(x);
newnode->pre = pos->pre;
newnode->next = pos;
pos->pre->next = newnode;
pos->pre = newnode;
}
//删除pos
void ListErase(ListNode* pos)
{
assert(pos);
ListNode* pre = pos->pre;
ListNode* cur = pos->next;
pre->next = cur;
cur->pre = pre;
free(pos);
}
2. 顺序表与链表的区别
区别 | 顺序表 | 链表 |
---|---|---|
物理空间上 | 物理空间上连续 | 逻辑上连续 ,但物理空间上不一定连续 |
随机插入时 | 可能需要进行大量挪动空间的操作,效率低 | 可以直接进行插入 |
扩容时 | 需要重新申请一段更大的新的连续的空间 | 利用碎片化的空间 |
应用场景 | 大量数据的存储,对存储元素的高频率访问 | 进行多次的插入删除操作 |