当前位置: 首页 > news >正文

零基础入门C语言之C语言实现数据结构之双向链表

在阅读本文之前,建议读者有限阅读专栏内前面部分的文章

目录

前言

一、双向链表的结构

二、双向链表的实现

总结


前言

本文主要介绍与C语言数据结构中双向链表部分有关的知识。


一、双向链表的结构

需要注意,这里的“带头”跟前面我们说的“头节点”是两个概念,实际前面的在单链表阶段称呼不严谨,但是为了读者更好的理解就直接称为单链表的头节点。 带头链表里的头节点,实际为“哨兵位”,哨兵位节点不存储任何有效元素,只是站在这里“放哨的”。 “哨兵位”存在的意义就是遍历循环链表避免死循环。

二、双向链表的实现

要实现双向链表,并且是带头双向循环链表,我们就需要首先先确定一下它的结构。

typedef int	LTDataType;
typedef struct ListNode {LTDataType data;struct ListNode* next;struct ListNode* prev;
}LTNode;

然后我们来实现一下它的初始化,但与我们之前学的单链表不同的是,它的初始化是需要先申请一个哨兵位的,而哨兵位的两个指针我们需要想一想是否可以定义为空指针。答案是不可以的,因为如果这样,就无法满足我们循环的定义了。所以我们请读者思考一下,如何实现上述思路呢?我给出代码示例如下:

LTNode* LTBuyNode(LTDataType x) {LTNode* node = (LTNode*)malloc(sizeof(LTNode));if (node == NULL) {perror("malloc failed");exit(1);}else {node->data = x;node->next = node;node->prev = node;}return node;
}
void LTInit(LTNode** pphead) {*pphead = LTBuyNode(-1);
}

然后我们写代码来测试一下:

#include "List.h"void ListTest01() {LTNode* plist = NULL;LTInit(&plist);
}int main() {ListTest01();return 0;
}

我们进入调试界面来看看是否完成了初始化:

可以看到是成功了的。

然后我们该如何实现它的尾插呢,相对来说这是一个比较简单的函数,请读者直接思考代码,我给出示例:

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;
}

同时为了方便观察,我们写出打印列表的代码,如下:

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

我们插入5个数据并打印出来试试:

我们接下来再来尝试下头插如何实现,请读者先行思考,我们给出示例代码:

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

我们插入5个数据看看:

代码此时没有问题。

在此之后,我们来实现一下链表的头删和尾删,同样与前面的思路类似,请读者自行思考,我给出示例代码:

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

然后我们分别头删和尾删3个数据,来测试一下:

然后我们来实现一下在指定位置之后插入数据,但在此之前我们需要实现一下找到这个位置的查找方法:

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

那么实现这个方法之后,我们就可以来测试一下指定位置之后插入函数:

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

可以看到实现结果如下:

然后与之相似的就是删除指定位置的节点,我们给出示例代码如下:

void LTErase(LTNode* pos) {assert(pos);pos->prev->next = pos->next;pos->next->prev = pos->prev;free(pos);pos = NULL;
}

我们试着删除存储0这个节点,其结果如下:

然后就是我们最后的链表的销毁操作:

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

所以,相对来说双向链表方法的实现是要比单链表简单许多,至少不会出现很多的循环,这大大减少了我们运行的时间。二者优缺点对比如下:


总结

本文介绍了C语言中双向链表的实现方法,重点讲解了带头双向循环链表的结构特点和使用哨兵位节点的必要性。文章详细阐述了双向链表的初始化、插入(头插、尾插、指定位置插入)、删除(头删、尾删、指定位置删除)、查找以及销毁等操作的实现原理,并提供了完整的代码示例。通过调试测试验证了各函数的正确性,展示了双向链表相比单链表的操作优势,特别是在避免循环和减少时间复杂度方面的改进。

http://www.dtcms.com/a/600724.html

相关文章:

  • 初次接触 LoRA 技术
  • 西安哪家网站公司做的比较好做网页制作的价格
  • 【OpenCV + VS 】图像通道分离与合并
  • 【超分辨率专题】HYPIR:扩散模型先验与 GAN 对抗训练相结合的新型图像复原框架
  • 【ZeroRange WebRTC】kvsWebrtcClientMaster 获取 ICE 服务器配置解析
  • 手机网站建设liednswordpress改模板教程视频
  • Chrome V3 插件开发:监听并转发 API 请求
  • OpenCV 图像处理与键盘交互
  • 长沙理工《人工智能基础A》实验(上机)报告实验三 电商数据可视化/图像处理
  • Elasticsearch 的结构化文档配置 - 递归分块实践
  • 如何在IIS中配置HTTP重定向
  • elasticsearch 安装 repository-oss 插件
  • 宝安做网站哪家好德阳网站建设熊掌号
  • 输入10个整数存放于数组中,并将最小的数与数组的第一个元素交换,最大的数与数组的最后一个元素交换
  • 从 WAL 到 Fluss->Flink CDC Postgres Connector 端到端同步实战
  • 数据结构 图 的邻接表建立
  • C++CUDA实战:通过两个图像算法,搞懂了GPU编程
  • RabbitMQ应用(2)
  • Spring Boot 中的消息队列集成:从 RabbitMQ 到 Kafka 的深度实践
  • Spring Boot 与 RabbitMQ 集成示例
  • 家纺 网站模版想自己做网站流程
  • 将 CentOS 风格的命令行提示符(如 [root@slave1 ~]#)修改为 Ubuntu 风格
  • k8s各种场景下排错思路以及命令 k8s常见问题故障处理思路
  • win32k源代码分析之win32k!IsSAS函数中的全局变量win32k!gfsSASModifiers = 3是什么时候被赋值的
  • 序列和可迭代
  • 16.udp_socket(二)
  • 如何在不使用iTunes的情况下在电脑上访问iPhone文件
  • python+websockets,报错RuntimeError: no running event loop
  • 自己做网站流程龙口市最新公告
  • 自助建站系统介绍wordpress 百度推广