当前位置:网站首页>双向带头循环链表实现
双向带头循环链表实现
2022-08-04 09:47:00 【kocc】
带头双向循环链表的实现
定义
typedef int LTDataType;
typedef struct ListNode
{
LTDataType data;
struct ListNode* next;//指针指向后一个结点
struct ListNode* prev;//指向前一个结点
}LTNode;
就像这样: (图拙)—_—!
实现
初始化
创建一个新结点当头结点,返回这个头结点,就当作初始化了
LTNode* ListCreate()
{
LTNode* phead = (LTNode*)malloc(sizeof(LTNode));
assert(phead);
phead->prev = phead;
phead->next = phead;//头指针指向自己,尾指针也指向自己
return phead;//返回头
}
打印
没什么好说的 遍历即可
void ListPrint(LTNode* phead)
{
assert(phead);
LTNode* cur = phead->next;//从头结点的next开始遍历
while (cur != phead)
{
printf("%d ", cur->data);
cur = cur->next;
}
printf("\n");
}
创建一个新结点
所有插入的前提,要创建出来一个新结点,我们把它封装成一个函数
LTNode* BuyLTNode(LTDataType x)
{
LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));
assert(newnode);
newnode->data = x;
newnode->next = newnode->prev = NULL;
return newnode;
}
尾插
void ListPushBack(LTNode* phead, LTDataType x)
{
assert(phead);
LTNode* newnode = BuyLTNode(x);//创建新结点
LTNode* tail = phead->prev;先把尾存起来
tail->next = newnode;把尾的next指向新结点
newnode->prev = tail;新结点的prev指向尾
newnode->next = phead;新结点的next指向头
phead->prev = newnode;头的prev指向新结点
}
尾删
void ListPopBack(LTNode* phead)
{
assert(phead);
LTNode* tail = phead->prev;//被删的尾
LTNode* newtail = tail->prev;//新的尾
free(phead->prev);//把尾删了
phead->prev = NULL;//安全
phead->prev = newtail;//把头的prev指向新的尾
newtail->next = phead;//新的尾的next指向头
}
头插
void ListPushFront(LTNode* phead, LTDataType x)
{
LTNode* newnode = BuyLTNode(x);
LTNode* prev= phead->prev;//先把尾存起来
newnode->next = phead;//新头的next指向头
phead->prev = newnode;//头的prev指向新头
prev->next = newnode;//尾的next指向新头
newnode->prev = prev;//新头的prev指向尾
}
头删
删除的是头结点的下一个结点
void ListPopFront(LTNode* phead)//删除头结点的下一个结点
{
assert(phead);
assert(phead->next != phead);
LTNode* newhead = phead->next;
LTNode* next = newhead->next;
phead->next = next;
next->prev = phead;
free(newhead);
newhead = NULL;
}
查找一个数
没啥好说,遍历,跟打印一样
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;
}
在某个数字前插入
这个函数往往和find函数配合起来一起用,find找到那个数字返回该结点地址
void ListInsert(LTNode* pos, LTDataType x)
{
assert(pos);
LTNode* newnode = BuyLTNode(x);
LTNode* posPrev = pos->prev;
//跟头插非常相似
newnode->next = pos;
pos->prev = newnode;
posPrev->next = newnode;
newnode->prev = posPrev;
}
删除某个数字
void ListErase(LTNode* pos)
{
assert(pos);
LTNode* posPrev = pos->prev;
LTNode* posNext = pos->next;
posPrev->next = posNext;
posNext->prev = posPrev;
pos = NULL;
}
总结
总体来讲,双向带头循环虽然结构最为复杂,但是实现较为容易,并且实现也较为清晰,其各方面的效率也相当之优秀,是一个较为出色的数据结构。
边栏推荐
- How to restore the Youxuan database with only data files
- 云函数实现网站自动化签到配置详解【Web函数/Nodejs/cookie】
- TCP协议 - 三次握手 - 四次挥手-内核参数调优
- Producer and Consumer Problems in Concurrent Programming
- leetcode经典例题——56.合并区间
- Interview at 14:00 in the afternoon, I came out at 14:08 with my head down, asking too much...
- No module named 'flask_misaka' has been resolved [BUG solution]
- 一文带你了解 ESLint
- LVS+Keepalived群集部署
- Could you please talk about how the website is accessed?[Interview questions in the web field]
猜你喜欢
随机推荐
MindSpore:图算融合报错
什么是元宇宙?
TiCDC迁移-TiDB到MySQL测试
Detailed explanation of telnet remote login aaa mode [Huawei eNSP]
三层交换机/路由器OSPF配置详解【华为eNSP实验】
浅聊偏函数
参数优化文档介绍
KubeDNS 和 CoreDNS
Get the number of cpu cores
获取cpu的核数
MindSpore:mirrorpad算子速度过慢的问题
leetcode经典例题——56.合并区间
数据使用要谨慎——不良数据带来严重后果
字符串相关题目
EastWave应用:自动计算光子晶体透反率
命里有时终须有--记与TiDB的一次次擦肩而过
TCP协议 - 三次握手 - 四次挥手-内核参数调优
LeetCode中等题之旋转图像
VSCode学习资料
路由/三层交换机DHCP下发地址详解【华为eNSP】