【数据结构】双向循环链表专题解析

实现自己既定的目标,必须能耐得住寂寞单干。💓💓💓

目录

•✨说在前面

🍋知识点一:双向链表的结构

 • 🌰1."哨兵位"节点

 • 🌰2.双向带头循环链表的结构

🍋知识点二:双向带头循环链表

 • 🌰1. 动态申请节点 

 • 🌰2. 双向链表的初始化

 • 🌰3. 双向链表元素的打印

 • 🌰4. 双向链表头部插入数据

 • 🌰5. 双向链表尾部插入数据

 • 🌰6. 指定位置pos之后插入数据

 • 🌰7.双向链表头部删除元素

 • 🌰8.双向链表尾部删除元素

 • 🌰9.删除指定位置pos节点

 • 🌰10.双向链表的查找

 • 🌰10.双向链表的销毁

• ✨SumUp结语


•✨说在前面

亲爱的读者们大家好!💖💖💖,我们又见面了,之前我们学习了顺序表后,又紧接着给大家讲解了链表中最典型的单向不循环链表,也是最常用的一种。但正所谓我们学习应该面面俱到,有了之前的学习基础,再学习双向链表实际上是非常简单的。

  

 如果你没有准备好的话,可以再复习一下单链表以及单链表相关LeetCode的OJ题。

   

👇👇👇
💘💘💘知识连线时刻(直接点击即可)

  🎉🎉🎉复习回顾🎉🎉🎉

【数据结构】单链表专题详细分析

    

  博主主页传送门:愿天垂怜的博客

 

 

🍋知识点一:双向链表的结构

 • 🌰1."哨兵位"节点

哨兵位指的是链表中指向链表第一个节点的节点,哨兵位不存储任何有效元素,只是在那里放哨的,顾称为哨兵位节点

注意:

这里的"带头"跟前面我们说的"链表中的第一个有效节点"是两个概念,实际单链表的头结点不是第一个有效节点,而是哨兵位节点。

"哨兵位"存在的意义:

遍历循环链表避免死循环。

具体带头比不带头有什么优势可以看我上一篇文章中的合并有序链表。

LeetCode/NowCoder-链表经典算法OJ练习1

 • 🌰2.双向带头循环链表的结构

结构如下:

 由于"哨兵位"节点的存在,我们再实现这样的链表时可以省去一些内容:

🎉插入操作时,不需要检查是否在头部插入,因为哨兵节点作为头结点,总是存在。

🎉删除操作时,不需要处理删除的是否是头节点的情况,因为哨兵节点不会被删除。

🎉简化了代码,因为不需要为头节点和普通节点编写不同的处理逻辑。

类比单链表的结构,可以定义出节点数据为整型的双向带头循环链表节点:

typedef int LTDataType;typedef struct ListNode
{LTDataType data;struct ListNode* prev;//指向前一个节点struct ListNode* next;//指向后一个节点
}LTNode;

🍋知识点二:双向带头循环链表

 • 🌰1. 动态申请节点 

在双向带头循环链表提供的方法中,动态申请节点是必不可少的。

LTNode* LTBuyNode(LTDataType x)
{LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));if (newnode == NULL){perror("malloc");exit(1);}newnode->data = x;newnode->next = newnode->prev = newnode;
}

初始化双向链表其实就是创建头节点,那么就需要用到LTBuyNode来申请节点。由于是双向的,我们可以让它的next指针和prev指针先指向它自己。

那是否可以将哨兵位的next指针和prev指针初始化为NULL呢?答案是不行的。

如果哨兵位的前驱指针prev和后继指针next初始化为NULL,这样的链表虽然满足了双向,也满足了带头,但是不满足循环,所以不能这样初始化,因此在动态申请节点的时候,就让newnode的prev和next都指向它自己,这样就可以循环起来了。

 • 🌰2. 双向链表的初始化

初始化双向带头循环链表实际上就是创建"哨兵位"头节点。

写法1:传二级指针,函数为void型。

void LTInit(LTNode** pphead)
{*pphead = LTBuyNode(-1);
}

写法2:不传参 ,在函数中创建节点,函数为LTNode*型。

LTNode* LTInit()
{LTNode* phead = LTBuyNode(-1);return phead;
}

我们将其中存储的值设为-1,表示其为头节点,此时链表中只有一个头节点:

 • 🌰3. 双向链表元素的打印

打印双向链表中的所有节点数据。

void LTPrint(LTNode* phead)
{LTNode* pcur = phead->next;while (pcur != phead){printf("%d->", pcur->data);pcur = pcur->next;}printf("\n");
}

这个没什么好说的,和之前我们学习的单链表基本是一样的,不过是while循环的条件有所变化。我们如果初始化pcur为phead->next,那它循环完一轮之后会重新变成phead,此时就已经打印完成,不需要继续循环了。

 • 🌰4. 双向链表头部插入数据

向双向链表的头部插入节点和数据,指的是在头节点的后一个位置插入数据,而不是在头节点的前面(头插)。

void LTPushFront(LTNode* phead, LTDataType x)
{assert(phead);LTNode* newnode = LTBuyNode(x);newnode->prev = phead;newnode->next = phead->next;phead->next = newnode;newnode->next->prev = newnode;
}

双向带头循环链表的指针关系比较复杂,但是逻辑却很简单,我们一定要通过画图来理解,不要光看代码,这样是看不出东西的。

上述关系红色为先修改,蓝色为后修改。由于关系比较多,可以先从newnode入手,先处理newnode的prev和next指针,这样不会影响到原链表的结构。当设置完newnode时,如果先让phead的后继指针next指向newnode,那么图中红色所标注的phead->next不在是那个节点的地址,而是newnode的地址,此时它就应该是newnode->next。

 • 🌰5. 双向链表尾部插入数据

向双向链表的尾部插入节点和数据,可以理解为在图中的末尾插入数据,也可以理解为在头节点的前一个位置插入数据。

void LTPushBack(LTNode* phead, LTDataType x)
{assert(phead);LTNode* newnode = LTBuyNode(x);newnode->prev = phead->prev;newnode->next = phead;phead->prev->next = newnode;phead->prev = newnode;
}

由于是循环链表,画图的时候可以在节点顺序不改变的前提下灵活变换图像。

图1:

图2:


 两中图理解都是可以的,由于头节点的位置固定,上面两个图都是同一个双向链表。 

 • 🌰6. 指定位置pos之后插入数据

在指定位置pos的后面插入节点和数据,其实和头插方法很类似,甚至可以说头插其实就是pos后插入数据的一种特殊情况,只不过此时pos=phead而已。

void LTInsert(LTNode* pos, LTDataType x)
{assert(pos);LTNode* newnode = LTBuyNode(x);newnode->prev = pos;newnode->next = pos->next;pos->next = newnode;newnode->next->prev = newnode;
}

可以发现,代码也是及其类似。

 • 🌰7.双向链表头部删除元素

删除链表中的第一个有效节点,即删除头节点的后一个节点。

void LTPopFront(LTNode* phead)
{assert(phead && phead->next != phead);LTNode* del = phead->next;phead->next = del->next;del->next->prev = phead;free(del);del = NULL;
}

为了防止free释放后无法解引用找到下一个节点的问题,引入del保存要删除的节点的地址。

 • 🌰8.双向链表尾部删除元素

 删除双向链表中的最后一个数据,可以理解为删除图中末尾的数据,也可以理解为删除头节点前面一个数据。

void LTPopBack(LTNode* phead)
{assert(phead && phead->next != phead);LTNode* del = phead->prev;phead->next = del->prev;del->prev->next = phead;free(del);del = NULL;
}

两种画法和2.5思路一样,这里就画出一种,只要理解一种,另一种就很简单了。

 • 🌰9.删除指定位置pos节点

删除指定位置pos的节点,如法炮制。

void LTErase(LTNode* pos)
{//pos不能为哨兵位assert(pos);pos->next->prev = pos->prev;pos->prev->next = pos->next;free(pos);pos = NULL;
}

除了要保证pos不为NULL外,还需要保证pos不能为哨兵位,否则它不是有效节点。

 • 🌰10.双向链表的查找

查找链表中值为x的节点。

LTNode* LTFind(LTNode* phead, LTDataType x)
{LTNode* pcur = phead->next;while (pcur != phead){if (pcur->data == x){return pcur;}pcur = pcur->next;}return NULL;
}

定义pcur,利用while循环遍历一轮,如果有值为x的节点,则返回该节点,遍历一轮后若仍没有该节点,则返回空指针NULL。

 • 🌰10.双向链表的销毁

与单链表和顺序表的思想如出一辙,如法炮制。

void LTDestory(LTNode* phead)
{assert(phead);LTNode* pcur = phead->next;while (pcur != phead){LTNode* next = pcur->next;free(pcur);pcur = next;}free(phead);phead = NULL;
}

• ✨SumUp结语

数据结构的学习一定要多画图,多理解,多思考,切忌直接抄写代码,就认为自己已经会了,一定到自己动手,才能明白自己哪个地方有问题。

如果大家觉得有帮助,麻烦大家点点赞,如果有错误的地方也欢迎大家指出~

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/13112.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于java的超级玛丽游戏的设计与实现(论文 + 源码)

Java的超级玛丽游戏.zip资源-CSDN文库https://download.csdn.net/download/JW_559/89313347 基于java的超级玛丽游戏的设计与实现 摘要 近年来,Java作为一种新的编程语言,以其简单性、可移植性和平台无关性等优点,得到了广泛地应用。J2SE称…

华焰天下晋升质量管理三大体系和产品3C认证实力级

华焰天下,作为业界领先的新能源灶具企业,一直以来都致力于追求卓越的质量管理和产品创新。近日,华焰天下成功晋升为质量管理三大体系先进管理,并成功获得了产品3C认证,这标志着我们在质量管理和产品安全方面迈出了坚实…

ThreadLocal,一次到位

一、定义 ThreadLocal是线程私有变量&#xff0c;用于保存每个线程的私有数据。 那么什么情况下需要进行线程隔离 二、源码分析 public class ThreadLocalTest01 {ThreadLocal<Integer> t new ThreadLocal<>();public void test() {t.set(1);Integer integer…

传输层协议——TCP协议

TCP协议又叫传输控制协议&#xff0c;TCP/IP协议是计算机通信网络中目前使用最多的协议&#xff0c;同时也融入了生活的方方面面&#xff0c;不管是浏览网页使用的http/https协议、物联网设备使用的MQTT/MQTTS协议与下载文件使用的ftp协议、工业以太网中使用的Modbus TCP协议等…

JVM学习-虚拟机栈

虚拟机栈 每个线程创建时都会创建一个虚拟机栈&#xff0c;其内部保存一个个栈帧&#xff0c;对应一次次Java方法调用&#xff0c;栈是线程私有的。 生命周期: 与线程相同 作用 主管Java程序的运行&#xff0c;它保存方法的局部变量、部分结果、并参与方法的调用和返回。 …

254 基于matlab的钢筋混凝土非线性分析

基于matlab的钢筋混凝土非线性分析&#xff0c;根据梁本构关系&#xff0c;然后进行非线性分析&#xff0c;绘制弯矩-曲率曲线。可设置梁的截面尺寸、混凝土本构&#xff0c;钢筋截面面积等相关参数&#xff0c;程序已调通&#xff0c;可直接运行。 254 钢筋混凝土非线性分析 弯…

利用管道通信(pipe)测量进程间的上下文切换(context switch)开销

利用管道通信(pipe)测量进程间的上下文切换(context switch)开销 《https://pages.cs.wisc.edu/~remzi/OSTEP/cpu-mechanisms.pdf》 Measuring the cost of a context switch is a little trickier. The lmbench benchmark does so by running two processes on a single CPU…

qmake、CMake、make和Makefile

为了跟踪C工程的全部部分&#xff0c;要求有一种机制来精确地指定&#xff1a; 涉及的输入文件&#xff0c;如源代码文件&#xff1a;.cpp&#xff0c;头文件&#xff1a;.h建立程序时所需的工具&#xff0c;如编译器&#xff1a; g.exe&#xff0c;链接器&#xff1a;ld.exe&a…

哈夫曼编码的应用

数据结构与算法课的一个简单实验&#xff0c;记录一下&#xff0c;以供参考。 文章目录 要求测试样例统计字母出现次数建立哈夫曼树对字符编码对原文进行编码译码 要求 输入一段100—200字的英文短文&#xff0c;存入一文件a中。统计短文出现的字母个数n及每个字母的出现次数…

终于搞懂Linux 设备树中的#address-cells,#size-cells 和reg 属性

目录 一、前置知识 1. 处理器平台2. reg 属性的基本格式3. reg 属性的作用 reg 用法 二、#address-cells 和 #size-cells 属性 1. 示例1 2. 示例23. 示例3 一、前置知识 要理解#address-cells和#size-cell 这两个属性&#xff0c;就要先了解 reg属性。 1. 处理器平台 下…

VS2022如何添加现有项

以 想在队列里&#xff0c;使用堆栈的.c&#xff0c;.h文件 为例 目录 1.复制堆栈的.c&#xff0c;.h文件 ​编辑 2.打开队列所在项目的文件夹 3.粘贴堆栈的.c&#xff0c;.h文件 4.在头文件和源文件添加相应的堆栈的.c&#xff0c;.h文件 1.复制堆栈的.c&#xff0c;.h文件…

HCIP【VLAN综合实验】

目录 一、实验拓扑图&#xff1a; 二、实验要求&#xff1a; 三、实验思路&#xff1a; 四、实验步骤&#xff1a; 1、在交换机SW1,SW2,SW3配置VLAN和各个接口对应类型的配置 2、在路由器上面配置DHCP服务 一、实验拓扑图&#xff1a; 二、实验要求&#xff1a; 1、PC1 …

STK12 RPO模块学习(3)

一、Maintain NMC RPO Sequence Maintain Natural Motion Circumnavigation RPO序列在目标星和追踪星经历不同的力的情况下保持NMC。通常这种差异是由于阻力和太阳光压造成的。这些是主要不同力当执行接近任务的时候&#xff0c;因为重力和相对三体摄动力非常小当相对距离在10…

link.click()时浏览器报错The file at ‘data:image/png;base64,iVBORw

代码如下&#xff1a; const dataURL canvas.toDataURL({format: "png",width: 400,height: 400, });const link document.createElement("a"); link.download new Date().getTime();link.href dataURL; document.body.appendChild(link); link.click…

高压无源探头能测整流桥电压吗?

高压无源探头是用于测量高电压电路中信号的一种工具&#xff0c;它不需要外部电源供电。然而&#xff0c;对于测量整流桥电压&#xff0c;需要考虑几个因素以确定是否可以使用高压无源探头。 首先&#xff0c;让我们了解一下整流桥的基本原理。整流桥是一种电路&#xff0c;用…

STM32--HC-SR501 热释电人体红外感应模块

实物引脚图&#xff1a; 模块工作特性&#xff1a; 当人进入感应范围之后输出引脚输出高电平&#xff0c;人离开感应范围自动延时输出低电平 热释电效应&#xff1a; 热释电传感器&#xff0c;也称为人体红外传感器&#xff0c;其工作原理基于热释电效应。这种传感器由几个关…

Rust中使用Rocket框架返回html网页,返回一个基于 Handlebars (HBS) 模板的响应

在Rust中使用Rocket框架返回网页&#xff0c;通常涉及创建一个路由&#xff0c;该路由将返回一个HTML页面。Rocket是一个快速、易用且可扩展的Web框架&#xff0c;它允许你以一种简洁的方式定义路由和处理请求。 一、使用Rocket框架返回一个简单的HTML页面&#xff1a; 添加依…

手机怎么下载别人直播间视频

手机下载直播视频&#xff0c;您需要按照以下步骤进行操作&#xff1a; 1. 打开直播平台&#xff0c;获取正在直播的链接&#xff0c;就是直播间的地址&#xff0c;然后粘贴在直接视频解析工具里&#xff0c;就可以同步下载直播视频画面。 2. 获取直播视频解析工具方法&#…

项目管理-案例重点知识(成本管理)

项目管理&#xff1a;每天进步一点点~ 活到老&#xff0c;学到老 ヾ(◍∇◍)&#xff89;&#xff9e; 何时学习都不晚&#xff0c;加油 三、成本管理 案例重点 成本管理 案例重点内容&#xff1a; &#xff08;1&#xff09;成本管理计划内容 &#xff08;2&#xff09;估算…

pcdn边缘云常见sla有哪些?如何避免被白嫖

PCDN&#xff08;Point-to-Point Content Delivery Network&#xff09;边缘云常见的SLA&#xff08;Service Level Agreement&#xff09;规则包括高峰期离线、服务时间、重传延时、限速等。这些规则是为了保证服务质量和用户体验。下面将详细解释这些规则&#xff0c;并提供一…