IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 数据结构-带头双向循环链表 -> 正文阅读

[数据结构与算法]数据结构-带头双向循环链表

目录

链表的分类

带头双向循环链表的概念及结构

概念

结构

带头双向循环链表的基本操作

初始化ListInit

尾插ListPushBack

头插ListPushFront

尾删ListPopBack

?头删ListPopFront

插入ListInsert

删除ListErase

查找ListFind

修改ListModify

打印ListPrint

长度ListSize

销毁ListDestroy

动态顺序表与带头双向循环链表的比较


链表的分类

? ?链表的种类非常丰富,有带头结点的或不带头结点的,有单向的或双向的,有循环的或非循环的,这样组合起来有2*2*2=8种链表结构。

? ?虽然有这么多的链表结构,但是我们实际中最常用的还是两种结构:

? ?最后我们再了解一下头结点与头指针的概念:不管带不带头结点,头指针都始终指向链表的第一个结点,而头结点是带头链表中第一个结点,该结点通常不存储数据。?

? ?引入头结点可以带来两个优点:1.由于第一个数据结点的位置被存储在头结点的指针域中,因此在链表的第一个位置上的操作和在链表其他位置上的操作一致,无须进行特殊处理。2.无论链表是否为空,其头指针都指向头结点,因此空表与非空表的处理也得到统一。


带头双向循环链表的概念及结构

概念

? ?链表是一种物理结构上非连续、非顺序的存储结构,数据元素的逻辑结构顺序是通过链表
中的指针链接次序实现的 。

? ?而带头双向循环链表是链表组合中最复杂的结构。

  • 因为是双向的,所以每个结点中有prev指针与next指针,其prev指针指向其结点的前一个结点,next指针指向其结点的后一个结点。
  • 并且拥有头结点,其头结点的next指向第一个数据结点,prev指向最后一个数据结点。
  • 又因为是循环结构,所以最后一个数据结点的next指向头结点。

结构

? ?带头双向循环链表的结点需要存储前一个结点地址的指针prev,存储后一个结点地址的指针next以及存储数据的data,这样的带头双向循环链表的结点结构才算完整。


带头双向循环链表的基本操作

初始化ListInit

? ?带头双向循环链表的初始化操作本质上就是开辟一个头结点并将头指针指向开辟好的头结点。? ? 有两种实现方法:1.将头指针传给ListInit在函数体内把头指针的指向改为头结点,所以需要用到二级指针,传头指针的地址才能改变头指针的指向。2.直接将开辟好的头结点地址作为返回值来改变头指针的指向。

? ?在这之前我们先实现一个开辟结点的函数,并将开辟好的结点中的prev和next指向自己。

尾插ListPushBack

? ?尾插就是在链表的最后一个数据结点的后面增添一个新结点,本质上就是将最后一个数据结点的next指向newNode,而newNode的prev指向最后一个数据结点,因为是循环结构,还需将头结点的prev指向newNode,而newNode的next指向头结点。

? ?与单链表相比,我们不需要遍历寻找最后一个数据结点,因为头结点的prev就是指向最后一个数据结点。

? ?当链表为空时,其操作也是一样的:

头插ListPushFront

? ?头插的操作就是将第一个数据结点的prev指向newNode,而newNode的next指向第一个数据结点,头结点的next指向newNode,而newNode的prev指向头结点。

? ?当链表为空时,其操作也是一样的。

尾删ListPopBack

? ?尾删的操作就是将最后一个数据结点的前一个结点的next指向头结点,而头结点的prev指向最后一个数据结点的前一个结点,然后释放掉最后一个数据结点。如果链表只剩下一个数据结点进行删除的话,操作也是一样的,尾删完最后一个结点就会回到头结点的next与prev指向自己的场景。

头删ListPopFront

? ?头删的操作就是将第一个数据结点的下一个结点的prev指向头结点,而头结点的next指向第一个数据结点的下一个结点,然后释放掉第一个数据结点。如果链表只剩下一个数据结点进行删除的话,操作也是一样的,头删完最后一个结点就会回到头结点的next与prev指向自己的场景。

插入ListInsert

? ?插入就是在pos位置前插入一个新结点,因为该链表为带头双向循环链表,所以我们可以直接找到pos位置的前一个结点,而不需要遍历找pos位置的前一个结点。具体操作就是将pos位置的前一个结点的next指向newNode,而newNode的prev指向pos位置的前一个结点,再将pos的prev指向newNode,而newNode的next指向pos即可完成插入操作。

? ? 实现插入操作后,我们的尾插与头插可以复用插入操作:

删除ListErase

? ?删除就是将pos位置的结点释放掉。具体操作就是将pos位置的前一个结点的next指向pos位置的后一个结点,而pos位置的后一个结点的prev指向pos位置的前一个结点,然后释放掉pos位置的结点。

? ??实现删除操作后,我们的尾删与头删可以复用删除操作:

查找ListFind

? ?按值查找就是将链表遍历一遍,并将查到存储该值的结点地址返回。

修改ListModify

? ?修改操作就是将pos位置的data数据改为x数据。

? ?将链表中所有存储2的结点改为存储0:

打印ListPrint

? ?之前单链表遍历的结束条件是curr是否等于NULL,因为最后一个数据结点的next指向NULL。而带头双向循环链表的遍历结束条件是curr是否等于phead,因为最后一个数据结点的next指向phead。?

长度ListSize

? ?求大小的操作同样是将链表遍历一遍,通过计数来求链表的长度。

? ?另一种求链表长度的方法: 将头指针与一个整形size封装到一个结构体中,当链表增加数据时size++,若链表减少数据时size--这样就不需要遍历。

销毁ListDestroy

? ?销毁的操作就是反复调用ListErase将所有的数据结点释放,最后将头结点也释放掉,调用ListDestroy之后记得将头指针置空。


动态顺序表与带头双向循环链表的比较

? ?动态顺序表

  • 优点:支持随机访问,缓存利用率高
  • 缺点:头部或者中间位置插入删除效率低,扩容有一定程度的性能消耗,也可能存在一定程度的空间浪费
  • 应用场景:频繁访问,高效存储

? ?带头双向循环链表

  • 优点:任意位置插入和删除的时间复杂度为O(1),按需申请释放
  • 缺点:不支持随机访问,缓存利用率低,会造成一定的内存碎片
  • 应用场景:频繁的任意位置插入删除
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-07-20 19:09:52  更:2022-07-20 19:11:35 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 23:47:48-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码