😎博客昵称:博客小梦
😊最喜欢的座右铭:全神贯注的上吧!!!
😊作者简介:一名热爱C/C++,算法等技术、喜爱运动、热爱K歌、敢于追梦的小博主!
😘博主小留言:哈喽!😄各位CSDN的uu们,我是你的博客好友小梦,希望我的文章可以给您带来一定的帮助,话不多说,文章推上!欢迎大家在评论区唠嗑指正,觉得好的话别忘了一键三连哦!😘
前言🙌
哈喽各位友友们😊,我今天又学到了很多有趣的知识,现在迫不及待的想和大家分享一下!😘我仅已此文,手把手带领大家学习C语言动态实现实现带头结点的双向循环链表结构~ 用代码来实现一个带头结点的双向循环链表结构,完成增删查改,顺序输出和逆序输出,判空的功能。都是精华内容,可不要错过哟!!!😍😍😍
预备小知识💞
链表的概念及结构🙌
链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链
接次序实现的 。
预备小知识💞
链表的概念及结构🙌
链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链
接次序实现的 。
带头结点的双向循环链表结构🙌
带头双向循环链表:结构最复杂,一般用在单独存储数据。实际中使用的链表数据结构,都是带头双向循环链表。另外这个结构虽然结构复杂,但是使用代码实现以后会发现结构会带来很多优势,实现反而简单了
整体实现内容分析💞
首先在头文件先定义结构体和各个功能函数的声明,并把有关的头文件包含上去。各个函数如何实现的,已在实验步骤描述清楚,这里就不在赘述了,主要是对各个函数的实现,用到malloc动态开辟新节点的空间,用assert断言确保指针有效,通过画图来帮助理清代码实现的思路,指针的指向如何,要考虑哪些情况。然后再测试代码中,将上述代码都进行测试,显示结果。
1.头文件编码实现🙌
1、 2、 #pragma once 3、 #include <stdio.h> 4、 #include <stdlib.h> 5、 #include <assert.h> 6、 #include <stdbool.h> 7、 8、 typedef int LTDataType; 9、 // 带头双向循环链表结构体 10、 typedef struct ListNode 11、 { 12、 struct ListNode* next; 13、 struct ListNode* prev; 14、 LTDataType data; 15、 }ListNode; 16、 ListNode* ListInit();//链表初始化 17、 void ListDestory(ListNode* phead);//删除链表 18、 void ListPrintFront(ListNode* phead);//链表顺序输出 19、 void ListPrintBack(ListNode* phead);//链表逆序输出 20、 void ListPushBack(ListNode* phead, LTDataType x);//尾插 21、 void ListPushFront(ListNode* phead, LTDataType x);//头插 22、 void ListPopFront(ListNode* phead);//头删 23、 void ListPopBack(ListNode* phead);//尾删 24、 ListNode* ListFind(ListNode* phead, LTDataType x);//查找 25、 void ListInsert(ListNode* pos, LTDataType x);// pos位置之前插入x 26、 void ListErase(ListNode* pos);// 删除pos位置的值 27、 bool ListEmpty(ListNode* phead);判空函数
2.代码功能实现🙌
1)这是生成新节点函数实现。😊
代码实现思路详解:
//用malloc动态开辟新节点的空间,把数值赋值给新节点
//,newnode的next和prev指针指向空。
ListNode* BuyListNode(LTDataType x) { ListNode* newnode = (ListNode*)malloc(sizeof(ListNode)); newnode->data = x; newnode->next = NULL; newnode->prev = NULL; return newnode; }
2)生成带头结点的空链表函数实现。😊
代码实现思路详解:
//2)生成带头结点的空链表,将头结点的指针都指向自己即可。
ListNode* ListInit() { ListNode* phead = BuyListNode(0); phead->next = phead; phead->prev = phead; return phead; }
3)删除链表函数实现。😊
代码实现思路详解:
//3)先用assert断言以下确保phead指针不为空,生成cur指针先指向第一个结点位置。用while循环执行删表:在定义一个next指针指向cur的下一个结点,free掉cur指向的结点,cur移动到next位置。最后删除头结点即可
//
void ListDestory(ListNode* phead)//删除链表 { assert(phead); ListNode* cur = phead->next; while (cur != phead) { ListNode* next = cur->next; free(cur); cur = next; } free(phead); phead = NULL; }
4)顺序输出链表函数实现。😊
代码实现思路详解:
//4)顺序输出链表。先assert断言确保指针有效。定义一个指向链表首结点的指针,打印完一个,cur到下一个节点知道cur回到phead为止。
void ListPrintFront(ListNode* phead) { assert(phead); ListNode* cur = phead->next; while (cur != phead) { printf("%d ", cur->data); cur = cur->next; } printf("\n"); }
5)尾插函数实现。😊
代码实现思路详解:
//5)尾插函数。先assert确保指针有效性,定义tail指针指向最后一个节点,然后生成新节点然后通过指针将tail指向的节点与新生成的节点相连,新生成的节点与哨兵位头结点相连
void ListPushBack(ListNode* phead, LTDataType x) { assert(phead); ListNode* tail = phead->prev; ListNode* newnode = BuyListNode(x); tail->next = newnode; newnode->prev = tail; newnode->next = phead; phead->prev = newnode; }