【数据结构和算法】实现带头双向循环链表(最复杂的链表)(上)

简介: 【数据结构和算法】实现带头双向循环链表(最复杂的链表)(上)

前言

带头双向循环链表,是链表中最为复杂的一种结构,我们主要实现的功能为,头插尾插,头删尾删,初始化、打印、指定pos位置插入结点或者删除结点、寻找结点、摧毁链表等函数。


一、带头双向循环链表是什么?

如图所示:


二、实现带头双向循环链表

1.结构体和要实现函数

结构体如下:

1. typedef struct DSLDataType;
2. //定义双向链表的结构体
3. 
4. //双向链表每一个节点都有一个前驱节点和后继节点,可以根据节点获得其前后的节点
5. typedef struct DSListNode {
6.  struct DSListNode* prev;//前驱节点
7.  struct DSListNode* next;//后继节点
8.  int value;//数据域
9. }DSLNode;//重定义

相比单向链表,多一个指针域prev,指向前面的结点地址

实现功能的函数:

1. //初始化
2. DSLNode*ListInit();
3. //打印链表
4. void ListPrint(DSLNode* ps);
5. //尾部插入
6. void ListPushBack(DSLNode* ps, int data);
7. //头部插入
8. void ListPushFront(DSLNode* ps, int data);
9. //尾部删除
10. void ListPopBack(DSLNode* ps);
11. //头部删除
12. void ListPopFront(DSLNode* ps);
13. //判空
14. bool ListEmpty(DSLNode* ps);
15. //返回链表节点个数
16. int Listsize(DSLNode* ps);
17. //寻找指定元素,返回对应的节点
18. DSLNode* ListFind(DSLNode* ps, int data);
19. //在pos之前插入节点
20. void ListInsert(DSLNode* pos, int data);
21. //删除pos位置结点
22. void ListEarse(DSLNode* pos);
23. //摧毁链表
24. void ListDestory(DSLNode* ps);

2.初始化和打印链表

1. //对于函数的实现
2. //初始化
3. DSLNode* ListInit() {
4.  //初始化创建链表
5.  //创建新节点
6.  DSLNode* num = (DSLNode*)malloc(sizeof(DSLNode));
7.  //判断是否创建成功
8.  if (num == NULL) {
9.    perror("malloc fail\n");
10.     exit(-1);
11.   }
12.   num->prev = num;
13.   num->next = num;//作为头节点,前驱和后驱结点都指向自己
14.   return num;
15. }
16. 
17. //打印链表
18. void ListPrint(DSLNode* ps) {
19.   assert(ps);//断言
20.   DSLNode* cur = ps->next;
21.   printf("phead->");
22.   while (cur != ps) {//双向链表,回到ps,就表示转了一圈
23.     printf("%d->", cur->value);
24.     cur = cur->next;
25.   }
26.   printf("NULL\n");
27. }

3.头插和尾插

尾插如图所示:

代码如下:

1. 
2. DSLNode* CreatNode(int data) {//创建新节点
3.  DSLNode* cur = (DSLNode*)malloc(sizeof(DSLNode));
4.  if (cur == NULL) {
5.    perror("malloc fail\n");
6.    exit(-1);
7.  }
8.  cur->next = cur->prev = NULL;
9.  cur->value = data;
10. }
11. //尾部插入
12. void ListPushBack(DSLNode* ps, int data) {
13.   assert(ps);//断言
14.   DSLNode* newnode = CreatNode(data);
15.   DSLNode* tail = ps->prev;//把头节点之前的那个地址给tail
16.   tail->next = newnode;//将ps之前的那个数值,实际上是这个双向链表的最后一个元素的位置,的next指针指向新节点
17.   newnode->prev = tail;//新节点前后为 tail和ps
18.   newnode->next = ps;
19.   ps->prev = newnode;//tail的两个指针域都指向完成,就只剩下ps的前驱指针
20. 
21. }

头插如图所示:

代码如下:

1. 
2. //头部插入
3. void ListPushFront(DSLNode* ps, int data) {
4.  assert(ps);
5.  //头部插入就是将ps之后的一个地址给临时变量tail
6.  DSLNode* tail = ps->next;
7.  DSLNode* newnode = CreatNode(data);//创建新节点
8.  ps->next->prev = newnode;
9.  newnode->next = ps->next;
10.     newnode->prev = ps;
11.     ps->next = newnode;
12. }

4.头删和尾删

尾部删除如图所示:

代码如下:

1. //判空
2. bool ListEmpty(DSLNode* ps) {
3.  assert(ps);//断言
4.  return ps->next == ps;//如果是只有一个ps头节点,则表示为空,返回true,否则返回false
5. 
6. }
7. //尾部删除
8. void ListPopBack(DSLNode* ps) {
9. 
10.   assert(ps);//断言
11.   assert(!ListEmpty(ps));//先判断是否为空
12.   DSLNode* cur = ps->prev;
13.   //将cur的next值为NULL
14.   ps->prev = ps->prev->prev;
15.   ps->prev->next = ps;
16.   //这是直接略过尾部最后一个元素
17.   //跳过ps之前的一个节点,先让其左右节点相连,然后释放这个地址
18.   free(cur);
19.   cur = NULL;
20. }

头部删除如图所示:

代码如下:

1. //头部删除
2. void ListPopFront(DSLNode* ps) {
3.  assert(ps);
4.  assert(!ListEmpty(ps));
5.  DSLNode* cur = ps->next;
6.  //头删  是将头节点之后的第一个节点删除释放空间
7.  ps->next = ps->next->next;
8.  ps->next->prev = ps;
9.  free(cur);
10.   cur = NULL;
11. }

5.查找和返回结点个数

查找:返回一个结点,根据data数值域,来返回第一个遇到的结点cur,若没有返回NULL

1. //返回链表节点个数
2. int Listsize(DSLNode* ps) {
3.  assert(ps);
4.  int count = 0;
5.  DSLNode* cur = ps->next;
6.  while (cur != ps) {
7.    count++;
8.    cur = cur->next;
9.  }
10.   return count;
11. }
12. //查找
13. DSLNode* ListFind(DSLNode* ps, int data) {
14.   assert(ps);
15.   DSLNode* cur = ps->next;
16.   while (cur != ps) {
17.     if (cur->value == data) {
18.       return cur;
19.     }
20.   }
21.   return NULL;//NULL表示不存在
22. }

6.在pos位置之前插入结点

如图所示:

代码如下:

1. //插入节点
2. void ListInsert(DSLNode* pos, int data) {
3. 
4.  assert(pos);
5.  //pos三种可能
6.  //1.空链表
7.  //2.只有一个节点
8.  DSLNode* cur = pos->prev;
9.  //双向链表可以直接找到pos之前的位置,单向链表只能进行循环
10.   DSLNode* newnode = CreatNode(data);
11.   pos->prev = newnode;//把新节点newnode的位置给pos的prev
12.   newnode->prev = cur;//cur表示的是创建new节点之前的时候pos之前的结点
13.   cur->next = newnode;
14.   newnode->next = pos;
15.   //另一种不使用cur的方法
16.   //newnode->next = pos;
17.   //pos->prev->next = newnode;
18.   //newnode->prev = pos->prev;
19.   //pos->prev = newnode;
20. }


相关文章
|
2月前
|
算法 数据处理 C语言
C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合
本文深入解析了C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合,旨在帮助读者掌握这一高效的数据处理方法。
61 1
|
2天前
|
机器学习/深度学习 存储 C++
【C++数据结构——线性表】单链表的基本运算(头歌实践教学平台习题)【合集】
本内容介绍了单链表的基本运算任务,涵盖线性表的基本概念、初始化、销毁、判定是否为空表、求长度、输出、求元素值、按元素值查找、插入和删除数据元素等操作。通过C++代码示例详细解释了顺序表和链表的实现方法,并提供了测试说明、通 - **任务描述**:实现单链表的基本运算。 - **相关知识**:包括线性表的概念、初始化、销毁、判断空表、求长度、输出、求元素值、查找、插入和删除等操作。 - **测试说明**:平台会对你编写的代码进行测试,提供测试输入和预期输出。 - **通关代码**:给出了完整的C++代码实现。 - **测试结果**:展示了测试通过后的预期输出结果。 开始你的任务吧,祝你成功!
20 5
|
2天前
|
存储 算法 测试技术
【C++数据结构——树】二叉树的遍历算法(头歌教学实验平台习题) 【合集】
本任务旨在实现二叉树的遍历,包括先序、中序、后序和层次遍历。首先介绍了二叉树的基本概念与结构定义,并通过C++代码示例展示了如何定义二叉树节点及构建二叉树。接着详细讲解了四种遍历方法的递归实现逻辑,以及层次遍历中队列的应用。最后提供了测试用例和预期输出,确保代码正确性。通过这些内容,帮助读者理解并掌握二叉树遍历的核心思想与实现技巧。
15 2
|
18天前
|
存储 运维 监控
探索局域网电脑监控软件:Python算法与数据结构的巧妙结合
在数字化时代,局域网电脑监控软件成为企业管理和IT运维的重要工具,确保数据安全和网络稳定。本文探讨其背后的关键技术——Python中的算法与数据结构,如字典用于高效存储设备信息,以及数据收集、异常检测和聚合算法提升监控效率。通过Python代码示例,展示了如何实现基本监控功能,帮助读者理解其工作原理并激发技术兴趣。
53 20
|
16天前
|
数据库
数据结构中二叉树,哈希表,顺序表,链表的比较补充
二叉搜索树,哈希表,顺序表,链表的特点的比较
数据结构中二叉树,哈希表,顺序表,链表的比较补充
|
2月前
|
存储 算法 搜索推荐
Python 中数据结构和算法的关系
数据结构是算法的载体,算法是对数据结构的操作和运用。它们共同构成了计算机程序的核心,对于提高程序的质量和性能具有至关重要的作用
|
2月前
|
数据采集 存储 算法
Python 中的数据结构和算法优化策略
Python中的数据结构和算法如何进行优化?
|
2月前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
71 1
|
4天前
|
算法 数据安全/隐私保护
室内障碍物射线追踪算法matlab模拟仿真
### 简介 本项目展示了室内障碍物射线追踪算法在无线通信中的应用。通过Matlab 2022a实现,包含完整程序运行效果(无水印),支持增加发射点和室内墙壁设置。核心代码配有详细中文注释及操作视频。该算法基于几何光学原理,模拟信号在复杂室内环境中的传播路径与强度,涵盖场景建模、射线发射、传播及接收点场强计算等步骤,为无线网络规划提供重要依据。
|
5天前
|
机器学习/深度学习 数据采集 算法
基于GA遗传优化的CNN-GRU-SAM网络时间序列回归预测算法matlab仿真
本项目基于MATLAB2022a实现时间序列预测,采用CNN-GRU-SAM网络结构。卷积层提取局部特征,GRU层处理长期依赖,自注意力机制捕捉全局特征。完整代码含中文注释和操作视频,运行效果无水印展示。算法通过数据归一化、种群初始化、适应度计算、个体更新等步骤优化网络参数,最终输出预测结果。适用于金融市场、气象预报等领域。
基于GA遗传优化的CNN-GRU-SAM网络时间序列回归预测算法matlab仿真