带头结点的循环双向链表看似复杂,但 实际结构操作起来要简单许多
头文件:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
结构:
typedef int LTDataType;
typedef struct ListNode
{
LTDataType data;
struct ListNode* prev;
struct ListNode* next;
}LTNode;
创建节点:
LTNode* BuyListNode(LTDataType x)
{
LTNode* newNode = (LTNode*)malloc(sizeof(LTNode));
newNode->data = x;
newNode->prev = NULL;
newNode->next = NULL;
return newNode;
}
初始化链表:
// 初始化一个空的链表-哨兵位
LTNode* ListInit()
{
// 做一个哨兵位的头结点 --> 不存储有效数据
LTNode* phead = (LTNode*)malloc(sizeof(LTNode));
phead->prev = phead;
phead->next = phead;
return phead;
}
插入pos之前函数:
// 在pos位置之前插入
void ListInsert(LTNode* pos, LTDataType x)
{
assert(pos);
LTNode* posPrev = pos->prev;
LTNode* newNode = BuyListNode(x);
newNode->prev = posPrev;
posPrev->next = newNode;
newNode->next = pos;
pos->prev = newNode;
}
删除pos函数:
// 删除pos位置的结点
void ListErase(LTNode* pos)
{
assert(pos);
assert(pos->next != pos);
LTNode* posPrev = pos->prev;
LTNode* posNext = pos->next;
posPrev->next = posNext;
posNext->prev = posPrev;
free(pos);
pos = NULL;
}
当写出了pos插入删除函数之后,头插,头删,尾插,尾删便可以直接进行调用了,来简化函数
尾插:
// 尾插
void ListPushBack(LTNode* phead, LTDataType x) // 不需要传二级指针,因为没有改变phead,只改变phead指向的结构体
{
assert(phead);
因为有了头结点,所以当链表为空,一样成立
//LTNode* tail = phead->prev; //链表的尾结点
申请一个新的结点
//LTNode* newNode = BuyListNode(x);
将新结点插入到尾结点之后
//newNode->prev = tail;
//tail->next = newNode;
//newNode->next = phead;
//phead->prev = newNode;
// 尾插相当于在phead的前面插入一个结点
ListInsert(phead,x);
}
尾删:
// 尾删
void ListPopBack(LTNode* phead)
{
assert(phead);
assert(phead->next != phead);
//LTNode* tail = phead->prev;
//LTNode* tailPrev = tail->prev;
//tailPrev->next = phead;
//phead->prev = tailPrev;
//free(tail);
// 尾删相当于删除phead的前一个结点
ListErase(phead->prev);
}
头插:
// 头插
void ListPushFront(LTNode* phead, LTDataType x)
{
assert(phead);
//LTNode* newNode = BuyListNode(x);
将新结点插入到头结点之后
//LTNode* next = phead->next;
//newNode->next = next;
//next->prev = newNode;
//newNode->prev = phead;
//phead->next = newNode;
// 头插相当于在phead的后面插入一个结点
ListInsert(phead->next, x);
}
头删:
// 头删
void ListPopFront(LTNode* phead)
{
assert(phead);
//链表为空
assert(phead->next != phead);
//LTNode* next = phead->next;
//LTNode* nextNext = next->next;
//phead->next = nextNext;
//nextNext->prev = phead;
//free(next);
// 头删相当于删除phead的后一个结点
ListErase(phead->next);
}
查找:
// 查找
LTNode* ListFind(LTNode* phead, LTDataType x)
{
assert(phead);
LTNode* cur = phead->next;
while (cur != phead)
{
if (cur->data == x)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
打印:
// 打印链表
void ListPrint(LTNode* phead)
{
assert(phead);
LTNode* cur = phead->next;
while (cur != phead)
{
printf("%d ", cur->data);
cur = cur->next;
}
printf("\n");
}
销毁:
// 销毁链表
void ListDestroy(LTNode* phead)
{
assert(phead);
LTNode* cur = phead->next;
while (cur != phead)
{
LTNode* next = cur->next;
free(cur);
cur = next;
}
free(phead);
}
主函数测试:
main()
{
// 创建一个空的链表
LTNode* plist = ListInit();
// 尾插
ListPushBack(plist, 1);
ListPushBack(plist, 2);
ListPushBack(plist, 3);
ListPushBack(plist, 4);
ListPrint(plist);
// 尾删
ListPopBack(plist);
ListPopBack(plist);
ListPrint(plist);
// 头插
ListPushFront(plist, 10);
ListPushFront(plist, 20);
ListPushFront(plist, 30);
ListPrint(plist);
// 头删
ListPopFront(plist);
ListPopFront(plist);
ListPrint(plist);
// 查找
LTNode* pfind = ListFind(plist, 1);
if (pfind)
{
printf("Find %d\n", pfind->data);
}
else
{
printf("Not Find\n");
}
// 删除pos位置的结点
LTNode* pos = ListFind(plist, 2);
if (pos)
{
ListErase(pos);
}
ListPrint(plist);
// 销毁链表
ListDestroy(plist);
plist = NULL;
return 0;
}