🌈 个人主页:白子寰
🔥 分类专栏:C++打怪之路,python从入门到精通,数据结构,C语言,C语言题集 👈 希望得到您的订阅和支持~
💡 坚持创作博文(平均质量分82+),分享更多关于深度学习、C/C++,python领域的优质内容!(希望得到您的关注~)
目录
双向循环链表
结构
包含数据域,指针域(前驱节点prev和后继节点next)
介绍
结构最复杂,一般用在单独存储数据。
实际中使用的链表数据结构,都是带头双向循环链表。
另外这个结构虽然结构复杂,
但是使用代码实现以后会发现结构会带来很多优势,但实现简单
图示
双向链表的实现
在List.h中
定义双向链表的结构
cs
typedef int LTDataType;
typedef struct ListNode
{
LTDataType data;
struct ListNode* prev;
struct ListNode* next;
}LTNode;
实现双向链表的接口/方法
cs
//初始化
LTNode* LTInit();
//销毁链表
void LTDestroy(LTNode* phead);
//打印链表
void LTPrint(LTNode* phead);
//判断链表是否为空
bool LTEmpty(LTNode* phead);
//尾插
void LTPushBack(LTNode* phead, LTDataType x);
//头插
void LTPushFront(LTNode* phead, LTDataType x);
//尾删
void LTPopBack(LTNode* phead);
//头删
void LTPopFront(LTNode* phead);
//在pos位置之后插入数据
void LTInsert(LTNode* pos, LTDataType x);
//删除pos指定节点
void LTErase(LTNode* pos);
//查找链表的指定元素
LTNode* LTFind(LTNode* phead, LTDataType x);
在List.c中
初始化
cs
//初始化
LTNode* LTInit()
{
LTNode* phead = LTBuyNode(-1);
return phead;
}
销毁链表
cs
//销毁
void LTDestroy(LTNode* phead)
{
assert(phead);
LTNode* pcur = phead->next;
while (pcur != phead)
{
LTNode* next = pcur->next;
free(pcur);
pcur = next;
}
//最后释放头节点的内存并置空
free(phead);
phead = NULL;
}
打印链表
cs
//打印双向链表
void LTPrint(LTNode* phead)
{
assert(phead);
LTNode* pcur = phead->next;
while (pcur != phead)
{
printf("%d->", pcur->data);
pcur = pcur->next;
}
printf("\n");
}
判断链表是否为空
cs
bool LTEmpty(LTNode* phead)
{
if (phead->next == phead)
{
return true;
}
else { return false; }
}
尾插
cs
//尾插
void LTPushBack(LTNode* phead, LTDataType x)
{
assert(phead);
LTNode* newnode = LTBuyNode(x);
newnode->next = phead;
newnode->prev = phead->prev;
phead->prev->next = newnode;
phead->prev = newnode;
}
后四行的方向和赋值问题
有新开节点newnode
测试
头插
cs
//头插
void LTPushFront(LTNode* phead, LTDataType x)
{
assert(phead);
LTNode* newnode = LTBuyNode(x);
LTNode* pcur = phead->next;
newnode->next = pcur;
newnode->prev = phead;
phead->next = newnode;
pcur->prev = newnode;
}
测试
尾删
cs
//尾删
void LTPopBack(LTNode* phead)
{
assert(phead);
LTNode* p1 = phead->prev;
LTNode* pcur = p1->prev;
pcur->next = phead;
phead->prev = pcur;
free(p1);
p1 = NULL;
}
测试
头删
cs
//头删
void LTPopFront(LTNode* phead)
{
assert(phead);
LTNode* pcur = phead->next->next;
LTNode* p1 = phead->next;
phead->next = pcur;
pcur->prev = phead;
free(p1);
p1 = NULL;
}
测试
在pos位置之后插入数据
cs
//在pos位置之后插入数据
void LTInsert(LTNode* pos, LTDataType x)
{
assert(pos);
LTNode* newnode = LTBuyNode(x);
newnode->next = pos->next;
newnode->prev = pos;
//如果pos是最后一个节点
if (pos->next == NULL)
{
newnode->next = NULL;
}
else
{
pos->next->prev = newnode;
}
pos->next = newnode;
}
测试
删除pos指定节点
cs
//删除pos节点
void LTErase(LTNode* pos)
{
assert(pos);
LTNode* p1 = pos->prev;
LTNode* pcur = pos->next;
p1->next = pcur;
pcur->prev = p1;
free(pos);
pos = NULL;
}
测试
查找链表的指定元素
cs
//查找元素
LTNode* LTFind(LTNode* phead, LTDataType x)
{
assert(phead);
LTNode* pcur = phead->next;
while (pcur != phead) //注意循环条件!
{
if (pcur->data == x)
{
return pcur;
}
else
{
pcur = pcur->next;
}
}
return NULL;
}
***********************************************************分割线*****************************************************************************
完结!!!
感谢浏览和阅读。等等等等一下,分享最近喜欢的一句话:
"人生如逆旅,我亦是行人"。
我是白子寰,如果你喜欢我的作品,不妨你留个点赞+关注让我知道你曾来过。
你的点赞和关注是我持续写作的动力!!!好了划走吧。