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

C语言数据结构:链表进阶(环形链表、双向链表、内核链表)与队列详解

上一篇讲解了单向链表基础:结构体封装、头插、尾插、尾删、valgrind 内存泄漏检测。本篇继续拓展环形链表判环、环长、环入口、双向链表、Linux 内核链表、链式队列,配套原理推导、核心逻辑,适合期末复习、嵌入式 C 面试准备。

一、单向链表 —— 环形链表问题

单向链表尾结点不再指向NULL,指向链表内部某个结点,就形成带环链表。常见三道面试题:判断是否有环、求环的长度、求环的入口点,核心算法:快慢指针(双指针)

1. 判断链表是否有环:快慢指针法

  • 定义两个指针:pfast快指针,pslow慢指针,都从链表头出发。

  • 慢指针pslow每次走 1 步;快指针pfast每次走 2 步

  1. 如果快指针走到NULL,链表无环;

  2. 如果快慢指针在链表中相遇,链表一定存在环。

原理:环内,快指针速度大于慢指针,快指针会不断追赶慢指针,环内一定会相遇;无环链表快指针会率先抵达末尾NULL

2. 求有环链表的环长

环长:环形部分包含结点数量

  1. 快慢指针得到相遇点;

  2. 指针从相遇点开始遍历,循环计数;

  3. 当指针再次回到相遇点,统计得到结点个数就是环的长度

3. 求环形链表环的入口结点(经典数学推导)

设:

  • l:链表头到环入口的结点距离;

  • a:环入口到快慢指针相遇点距离;

  • b:相遇点回到环入口的距离; 环总长:L = a + b

相遇时:

  • 慢指针路程:s = l + a

  • 快指针路程:2s = l + a + k*(a+b),k 为快指针在环内绕的圈数

联立化简,得到关键结论:l = b

✅数学结论:链表起点到环入口距离 = 相遇点到环入口距离

算法实现步骤:

  1. 得到快慢指针相遇结点;

  2. 一个指针从相遇点出发,另一个指针从链表头部出发;

  3. 两个指针每次都只走一步;

  4. 两个指针第一次相遇的结点,就是环形链表的环入口

⚠️注意:必须两个指针都一次走一步,不能继续快慢速度。

二、双向链表

单向链表结点只有后继指针pnext,只能向后遍历;双向链表每个结点增加前驱指针ppre,既可以向后遍历,也可以向前回溯。

1. 双向链表结构体定义

//数据域,可以自定义存储任意业务数据 typedef struct stu { char name[32]; int age; int score; }Data_t; //双向链表结点:前驱+后继+数据 typedef struct dnode { Data_t data; struct dnode *ppre; //指向前驱结点 struct dnode *pnext; //指向后继结点 }DNode_t; //双向链表管理对象,封装头指针与链表长度 typedef struct dlink { DNode_t *phead; int clen; }DLink_t;

2. 双向链表优缺点

✅优点

  1. 支持正向、反向双向遍历;

  2. 已知某结点,可以直接找到它的前驱结点,单向链表必须从头遍历;

  3. 删除当前结点时,不需要遍历找前驱。

❌缺点

  1. 每个结点多一个指针域,内存开销变大

  2. 插入、删除结点,要维护两个指针(ppre、pnext),代码逻辑比单链表复杂,指针顺序容易写错。

3. 双向链表 API 接口清单

  1. 创建双向链表

  2. 结点插入(头插、尾插、按位置插入)

  3. 结点删除

  4. 结点查找

  5. 结点数据修改

  6. 正向 / 反向遍历链表

  7. 链表销毁(循环 free 所有结点,释放链表对象,防止内存泄漏)

💡易错提醒:双向链表插入删除,要同时修改新结点、相邻结点的pprepnext,指针赋值顺序不能乱。

三、Linux 内核链表

内核链表本质:双向循环链表,Linux 内核大量使用。

和普通双向链表核心区别

  1. 普通链表:结点内部包含数据域结点把业务数据直接包在结构体里面,一旦写死数据类型,链表就只能存这一种数据。如果要存新的数据类型,需要重新写一套链表代码。

  2. 内核链表:链表节点嵌入业务结构体

链表的pprepnext指针不包裹数据;把链表小结构体,嵌入到你自己业务结构体内部。 同一套链表代码,可以挂载任意不同类型业务结构体,代码复用性极强。

核心两个内核宏:

  1. offsetof(TYPE, MEMBER)获取结构体成员,距离结构体起始地址的字节偏移量

  2. container_of(ptr, type, member)已知嵌入的链表成员地址,结合偏移量,反向得到整个业务结构体的首地址

工作流程:通过链表指针 → container_of + offsetof → 拿到外层完整业务结构体。

内核链表没有 data 域,只负责串起结构体;业务数据放在外层结构体。一套链表算法适配多种数据类型,驱动、内核模块广泛使用。

四、队列(Queue)

1. 队列基础概念

队列是线性结构,特性:FIFO 先进先出

  • 队尾:执行插入操作,叫入队

  • 队头:执行删除操作,叫出队

类比排队:先排队的人,先离开队伍。

2. 队列分类

  1. 顺序队列:数组实现,存在假溢出问题,一般优化为循环队列

  2. 链式队列:链表实现,本篇重点

链式队列管理结构体,一般保存:

  • phead:队头指针(出队在这里删结点)

  • ptail:队尾指针(入队在这里新增结点)

  • clen:当前队列元素个数

3. 链式队列核心操作

  1. 入队(队尾插入结点)新结点加到ptail后面,更新队尾指针ptail指向新结点;队列为空时,pheadptail都指向新结点。

  2. 出队(队头删除结点)删除phead指向的队头结点,更新队头指针; ⚠️边界:删除之后队列为空,需要将ptailNULL,避免野指针。

4. 队列 API

  1. 创建队列

  2. 入队

  3. 队列遍历

  4. 判断队列是否为空

  5. 出队

  6. 获取队头元素(只读取,不删除)

  7. 销毁队列:释放全部结点、释放队列管理对象

5. 队列典型应用场景

数据缓冲、任务排队、消息队列,生产者消费者模型。

知识点总结思维导图

  1. 环形单向链表

  • 判环:快慢指针;有环则相遇,无环 fast 走到 NULL

  • 环长:相遇点循环计数回到原点

  • 环入口:头指针、相遇点指针,同速步进,相遇即入口,数学推导l=b

  1. 双向链表每个结点:ppre前驱指针 +pnext后继指针;双向遍历;插入删除维护两组指针,内存开销增大。

  2. 内核双向循环链表链表结点嵌入业务结构体;offsetof求偏移,container_of反向获取结构体首地址;一套链表操作支持多种数据类型。

  3. 队列 FIFO 先进先出队尾入队,队头出队;链式队列维护头指针、尾指针;常用于缓冲、消息队列。


拓展思考(面试常考)

  1. 快慢指针为什么快指针每次走 2 步,走 3 步行不行?

可以,但 2 步是最简单;步长过大,会增加错过相遇的概率,2 步是最优。

  1. 双向链表删除结点相比单向链表优势?

单向链表删除当前结点,需要从头遍历找前驱;双向链表直接node->ppre拿到前驱。

  1. 内核链表相比普通链表最大优势是什么?

代码复用,不需要为每种数据类型重写一套链表插入删除。

  1. 链式队列出队后,什么时候 ptail 要置 NULL?

删除之后队列变空,如果不置空,ptail 会变成野指针,下次入队会产生逻辑错误。下一篇可以完整实现:环形链表判环代码、双向链表全套接口、内核链表模拟实现、链式队列完整 C 代码。

http://www.jsqmd.com/news/1402418/

相关文章:

  • EventOS事件驱动框架:从原理到实战,构建高内聚低耦合的现代应用架构
  • AI Agent记忆系统设计:从向量检索到混合架构的工程实践
  • VSCode前端插件生态:从原理到实践的系统化构建与管理指南
  • AI智能体防幻觉实战:从RAG优化到四层架构的工程化解决方案
  • Tushare Skills:从数据API到分析技能平台的进化与实践指南
  • 2026年8月佛山脚手架钢材/预埋件钢材厂家优选推荐_佛山市团铸钢铁有限公司 - 品牌宣传支持者
  • AI Coding 项目案例:企业组织架构与 RBAC 权限管理系统
  • Windows蓝屏死机全解析:从错误码解读到软硬件深度排查指南
  • ROS机器人开发中tf2坐标系变换:从核心原理到工程实践
  • 自动焊接设备出片品质哪家高,2026十大品牌深度测评,所见即所得不踩雷 - myqiye
  • 国产模型代码审查翻车:Cursor 误报率 37% 的秘密测试集
  • 从零构建工程师式AI工作流:以博客评估Agent为例
  • 2026年8月评价高的铝压铸生产厂家口碑推荐分析,铝合金高压压铸/锌铝压铸/铝压铸/铝合金压铸,铝压铸企业怎么选择 - 企业权威推荐大使
  • 从OpenClaw看AI Agent三阶段进化:从工具编排到自主智能
  • Spring AI 2.0:RAG
  • 2026年8月广东C型钢铁材料/钢铁材料厂家推荐案例_佛山市团铸钢铁有限公司 - 行业平台推荐
  • [封装科普] 芯片先进封装解析:SiP 架构、PoP 焊接工艺与后段封装核心技术
  • NuGet存储路径深度解析:从原理到实践,优化.NET开发环境与CI/CD构建
  • 前端网络请求封装:架构设计与性能优化实践
  • 小龙虾烹饪全攻略:从选虾处理到麻辣蒜蓉风味实战
  • Vibe Coding 构建百万文档 RAG:冷热分层后 API 响应仍暴增 2000ms——我的三层索引止血术
  • Hermes Agent 解决的核心问题是什么?
  • 260815周H热泵项目
  • 从零到一搭建智能客服系统(LangGraph + FastAPI + 智谱AI 实战)
  • 2026年上海旧房翻新翻新:刷新墙面三档报价,价差来自基层处理深度 - 优家闲谈
  • 四足机器人技术栈解析:从硬件到AI的工程化落地与商业思考
  • 书架排列问题(区间查询)
  • OpenClaw Agent Send:命令行驱动的多平台消息自动化投递工具实战指南
  • Linux上安装FFmpeg
  • 宇树科技IPO启示:从技术期权到机器人商业化的硬科技创业逻辑