带头双向循环链表-C语言
- 双向循环链表
- 双向循环链表结构
- 双向循环链表结构体创建
- 双向循环链表的创建
- 创建节点
- 创建返回链表的头结点
- 双向循环链表的尾插和尾删
- 尾插
- 尾删
- 双向循环链表的头插和头删
- 头插
- 头删
- 双向循环链表的中间插入和中间删除
- 中间插入
- 中间删除
- 双向循环链表的查找和打印
- 查找
- 打印
- 双向循环链表的销毁
- 销毁
- 总结
双向循环链表
双向带头循环链表
- 双向循环链表结构
双向循环链表结构
双向循环链表结构体创建
创建节点的结构体
struct ListNode
{
struct ListNode* prev;
int data;
struct ListNode* next;
}
//优化
typedef int LTDataType;
typedef struct ListNode
{
LTDataType data;
struct ListNode* next;
struct ListNode* prev;
}ListNode;
双向循环链表的创建
创建节点
ListNode* BuyListNode(LTDataType x)
{
//开辟一个新节点的空间
ListNode* newNode = (ListNode*)malloc(sizeof(ListNode));
if (newNode == NULL) // 判断是否开辟成功
{
perror("malloc fail");
exit(-1);
}
//初始化新节点后返回
newNode->data = x;
newNode->next = NULL;
newNode->prev = NULL;
return newNode;
}
开辟了一个新节点后,我们需要判断是否开辟成功,如果开辟成功后,将data放入新节点,新节点的prev和next初始化为空;
next为链接新节点后的一个节点;
prev为链接新节点前一个的节点;
创建返回链表的头结点
ListNode* ListCreate()
{
ListNode* phead = BuyListNode(-1);
phead->next = phead;
phead->prev = phead;
return phead;
}
头节点为哨兵位,创建一个头节点;
双向循环链表的尾插和尾删
尾插
void ListPushBack(ListNode* pHead, LTDataType x)
{
assert(pHead);
ListNode* newnode = BuyListNode(x);
ListNode* tail = pHead->prev;
tail->next = newnode;
newnode->prev = tail;
newnode->next = pHead;
pHead->prev = newnode;
}
尾删
void ListPopBack(ListNode* pHead)
{
assert(pHead); //判断是否为空
assert(pHead->next != pHead);//空
//删除的尾节点指针
ListNode* tail = pHead->prev;
//尾节点的前一个节点
ListNode* first = tail->prev;
//链接删除尾节点的前一个节点
pHead->prev = first;
first->next = pHead;
free(tail);
}
双向循环链表的头插和头删、
头插
void ListPushFront(ListNode* pHead, LTDataType x)
{
assert(pHead);
//创建新节点和找到头节点后面的节点
ListNode* newnode = BuyListNode(x);
ListNode* second = pHead->next;
//将新的节点链接进去
pHead->next = newnode;
newnode->prev = pHead;
newnode->next = second;
second->prev = newnode;
}
头删
void ListPopFront(ListNode* pHead)
{
assert(pHead);
assert(pHead->next != pHead);
//找到删除的节点
ListNode* delnode = pHead->next;
//找到删除节点的下一个节点
ListNode* node = delnode->next;
//将删除节点的下一个节点和头节点链接
pHead->next = node;
node->prev = pHead;
free(delnode); //释放删除节点
}
双向循环链表的中间插入和中间删除
中间插入
(双向链表在pos的前面进行插入)
void ListInsert(ListNode* pos, LTDataType x)
{
assert(pos);
//prev为pos的前一个的节点
ListNode* prev = pos->prev;
ListNode* newnode = BuyListNode(x);//创建新节点
//将新节点链接到prev后面 新节点next指向pos
prev->next = newnode;
newnode->prev = prev;
newnode->next = pos;
pos->prev = newnode;
}
中间删除
(删除pos位置的节点)
void ListErase(ListNode* pos)
{
assert(pos);
//找到pos的前后节点
ListNode* prev = pos->prev;
ListNode* next = pos->next;
free(pos);//释放pos
//将前后节点链接
prev->next = next;
next->prev = prev;
}
双向循环链表的查找和打印
查找
ListNode* ListFind(ListNode* pHead, LTDataType x)
{
assert(pHead);
ListNode* cur = pHead->next;
while (cur != pHead)
{
if (cur->data == x)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
打印
void ListPrint(ListNode* pHead)
{
assert(pHead);
ListNode* cur = pHead->next;
while (cur != pHead)
{
printf("%d ", cur->data);
cur = cur->next;
}
printf("\n");
}
双向循环链表的销毁
销毁
void ListDestory(ListNode* pHead)
{
assert(pHead);
ListNode* cur = pHead->next;
while (cur != pHead)
{
ListNode* next = cur->next;
free(cur);
cur = next;
}
free(pHead);
}
总结
带头双向循环链表结构最为复杂,但是使用代码实现以后会发现结构会带来很多优势,实现反而简单了。不管是插入删除都非常的方便。