前言
在前面的博客中,我们学习了单链表的实现与操作,但在实际操作的时候会发现有很多不方便的地方。接下来我来介绍双链表的相关知识。
带头双向循环链表的实现
双向循环链表与之前的单链表的区别:
- 单链表是不带头的,但双向循环链表是带头的
- 双向循环链表头尾相连,可以快速找到尾节点
typedef int LTDataType;
typedef struct LTNode
{
LTDataType data;
struct LTNode* prev;
struct LTNode* next;
}LTNode;
data用来储存数据,prev 指针用来存上个节点的地址,next 指针用来存下个节点的地址
创建新的节点
LTNode* BuyLTNode(LTDataType x)
{
LTNode* tmp = (LTNode*)malloc(sizeof(LTNode));
if (tmp == NULL)
{
perror("tmp");
return NULL;
}
tmp->data = x;
tmp->next = NULL;
tmp->prev = NULL;
return tmp;
}
创建头节点
LTNode* LTInit()
{
LTNode* tmp = BuyLTNode(-1);
tmp->next = tmp;
tmp->prev = tmp;
return tmp;
}
创建头节点时要使其自成循环,方便后面拼接
头插
void LTPushFront(LTNode* phead, LTDataType x)
{
assert(phead);
LTNode* tail = BuyLTNode(x);
LTNode* pheadNext = phead->next;
tail->next = pheadNext;
pheadNext->prev = tail;
tail->prev = phead;
phead->next = tail;
}
尾插
void LTPushBack(LTNode* phead, LTDataType x)
{
assert(phead);
LTNode* tail = BuyLTNode(x);
LTNode* pheadPrev = phead->prev;
tail->prev = pheadPrev;
pheadPrev->next = tail;
phead->prev = tail;
tail->next = phead;
}
判断链表是否只有头节点
bool LTEmpty(LTNode* phead)
{
assert(phead);
return phead == phead->next;
}
如果只有头节点,就不能删除了
打印
void LTPrint(LTNode* phead)
{
assert(phead);
printf("head <==> ");
LTNode* head = phead->next;
while (head != phead)
{
printf("%d<==>", head->data);
head = head->next;
}
printf("\n");
}
头删
void LTPopFront(LTNode* phead)
{
assert(phead);
assert(!LTEmpty(phead));
LTNode* head = phead->next;
LTNode* headNext = head->next;
phead->next = headNext;
headNext->prev = phead;
free(head);
}
尾删
void LTPopBack(LTNode* phead)
{
assert(phead);
assert(!LTEmpty(phead));
LTNode* tail = phead->prev;
LTNode* tailPrev = tail->prev;
tailPrev->next = phead;
phead->prev = tailPrev;
free(tail);
}
查询
LTNode* LTFind(LTNode* phead, LTDataType x)
{
assert(phead);
LTNode* tmp = phead->next;
while (tmp != phead)
{
if (tmp->data == x)
{
return tmp;
}
tmp = tmp->next;
}
return NULL;
}
删除pos节点
void LTErase(LTNode* pos)
{
assert(pos);
assert(!LTEmpty(pos));
LTNode* posNext = pos->next;
LTNode* posPrev = pos->prev;
posNext->prev = posPrev;
posPrev->next = posNext;
free(pos);
}
在pos位置之前插入X
void LTInsert(LTNode* pos, LTDataType x)
{
assert(pos);
LTNode* tail = BuyLTNode(x);
LTNode* posPrev = pos->prev;
tail->prev = pos->prev;
pos->prev = tail;
tail->next = pos;
posPrev->next = tail;
}
链表置空
void LTDestroy(LTNode* phead)
{
assert(phead);
LTNode* cur = phead->next;
while (cur != phead)
{
LTNode* tmp = cur->next;
free(cur);
cur = tmp;
}
free(phead);
}
运行实例
#include"List.h"
int main()
{
LTNode* s = LTInit();
LTPushFront(s, 1);
LTPushFront(s, 2);
LTPushFront(s, 3);
LTPushFront(s, 4);
LTPrint(s);
LTPopFront(s);
LTPrint(s);
LTDestroy(s);
return 0;
}