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

数据结构 - 双向链表

双向链表定义

双向链表的节点包含数据域和两个指针域(前驱指针prev、后继指针next),结构定义如下:

typedef int data_t; typedef struct node { data_t data; // 数据域 struct node *next; // 后继指针(指向后一个节点) struct node *prev; // 前驱指针(指向前一个节点) } node_t;

核心操作及实现思路

创建--增(插入)--删--改--查--销毁

创建双向链表(初始化头节点)

功能:创建空的双向链表,头节点的prevnext均设为NULL

node_t *creat_doublist(void) { node_t *phead = (node_t *)malloc(sizeof(node_t)); phead->prev = NULL; phead->next = NULL; return phead; }
判断链表是否为空
//判断是否为空的函数 int is_empty(node_t *phead) { return phead->next == NULL && phead->prev == NULL; } // int doublist_print(node_t *phead) { if(phead == NULL) { return -1; } node_t *p = phead->next; while(p!=NULL) //尾节点也需要打印,P要走到NULL { printf("%d ",p->data); p = p->next; } putchar('\n'); return 0; }
插入操作

双向链表的插入需注意前驱和后继指针的双向维护,分为头插和尾插。

头插法(在链表头部插入新节点)

步骤:

  • 创建新节点p_new,填充数据。
  • 调整指针(保证双向链接):
    • p_new->next = phead->next(新节点的后继指向原头节点的下一个节点)
    • p_new->prev = phead(新节点的前驱指向头节点)
    • phead->next = p_new(头节点的后继指向新节点)
    • 若原头节点有后继(p_new->next != NULL),则p_new->next->prev = p_new(原后继节点的前驱指向新节点)
void doublist_insert_head(node_t *phead, data_t data) { node_t *p_new = (node_t *)malloc(sizeof(node_t)); p_new->data = data; p_new->next = phead->next; p_new->prev = phead; phead->next = p_new; if (p_new->next != NULL) { p_new->next->prev = p_new; } }
尾插法(在链表尾部插入新节点)

步骤:

  • 创建新节点p_new,填充数据。
  • 找到链表的尾节点(遍历至p->next == NULL的节点)。
  • 调整指针:
    • p_new->next = p->next(新节点的后继设为NULL,因为尾插后新节点是尾)
    • p_new->prev = p(新节点的前驱指向原尾节点)
    • p->next = p_new(原尾节点的后继指向新节点)
遍历操作
  • 正向遍历:从head节点的next开始,依次访问next指针,直到NULL
  • 逆向遍历(逆序打印):从尾节点开始,通过prev指针反向访问,直到回到head节点。
查找操作

功能:根据给定值data,在链表中查找节点。

node_t *doublist_find_key(node_t *phead, data_t data) { node_t *p = phead->next; while (p != NULL) { if (p->data == data) { return p; } p = p->next; } return NULL; }
修改操作

功能:将链表中值为old的节点,修改为new

node_t *doublist_update_key(node_t *phead, data_t old, data_t new) { node_t *p = doublist_find_key(phead, old); if (p != NULL) { p->data = new; } return p; }
长度统计

功能:统计链表中有效节点(不含头节点)的个数。

int length(node_t *phead) { int count = 0; node_t *p = phead->next; while (p != NULL) { count++; p = p->next; } return count; }
销毁操作(可选但重要)

功能:释放链表所有节点的内存(包括头节点)。

void destroy_doublist(node_t *phead) { node_t *p = phead; while (p != NULL) { node_t *temp = p; p = p->next; free(temp); } }

双向链表的特点

  • 优点:支持双向遍历(可从前向后、从后向前),插入/删除时可快速定位前驱和后继,操作更灵活。
  • 缺点:每个节点多一个指针域,空间开销略大;插入/删除时需维护两个方向的指针,代码复杂度稍高。

示例:头插法完整代码

#include <stdio.h> #include <stdlib.h> typedef int data_t; // 假设数据类型为int typedef struct node { data_t data; struct node *next; struct node *prev; } node_t; // 创建空双向链表 node_t *creat_doublist(void) { node_t *phead = (node_t *)malloc(sizeof(node_t)); phead->prev = NULL; phead->next = NULL; return phead; } // 头插法插入节点 void doublist_insert_head(node_t *phead, data_t data) { node_t *p_new = (node_t *)malloc(sizeof(node_t)); p_new->data = data; p_new->next = phead->next; p_new->prev = phead; phead->next = p_new; if (p_new->next != NULL) { p_new->next->prev = p_new; } } // 遍历打印(正向) void print_doublist(node_t *phead) { node_t *p = phead->next; while (p != NULL) { printf("%d ", p->data); p = p->next; } printf("\n"); } int main() { node_t *phead = creat_doublist(); doublist_insert_head(phead, 1); doublist_insert_head(phead, 2); doublist_insert_head(phead, 3); print_doublist(phead); // 输出:3 2 1 destroy_doublist(phead); return 0; }
http://www.jsqmd.com/news/567781/

相关文章:

  • 多语言翻译工具:translategemma-27b-it在Ollama上的安装与体验
  • DLSS Swapper:解决游戏DLSS版本管理难题的一站式方案
  • VHD/VHDX 数据守护:BAT位图校验与修复
  • 影刀经验库征集|Deepseek+RPA的内容创作提效法
  • 基于InternLM2-Chat-1.8B的智能问答知识库构建:从文档录入到答案检索
  • Redis RDB文件高效分析实战指南
  • 第4章 载体选择:网站、小程序还是App?
  • Performance-Fish终极指南:快速解决《环世界》卡顿问题的完整方案
  • 确定了,百亿项目技术选型.NET
  • 全网最详细的AI大模型产品经理学习路线
  • 考虑电动汽车时空调度的配电网潮流优化MATLAB代码实现——基于He等2016年Applied...
  • Unpaywall终极指南:一键解锁全球学术论文的免费获取方案
  • 实战应用:通过快马平台开发一个趣味linux命令挑战游戏
  • AI测试技能卷起来!目标检测算法测试流程与方法总结
  • RAG系统知识库“过时“?这个反常识方法让检索效果提升2.14%,零成本迁移还不用改代码!
  • 不止于SOME/IP:用CANoe玩转车载以太网VLAN隔离与报文转发
  • 告别HEIC预览盲区:让Windows用户轻松驾驭苹果图像格式
  • 【threejs】八叉树优化下的第一人称视角碰撞检测实战
  • 安卓手机秒变AI开发神器:Aid Learning零基础图形化Linux环境搭建指南
  • 从数据到预测:如何用Bliss/HSA/Loewe/ZIP评分训练你的第一个药物协同AI模型?
  • VMware虚拟机彻底卸载指南:从服务终止到注册表清理
  • 告别手动配置:用快马AI一键生成OAuth Token管理代码,效率翻倍
  • 数据结构-堆 _
  • 嵌入式老鸟总结:Keil警告L15/L16的隐藏陷阱与RTOS适配技巧
  • leetcode 1544. 整理字符串-耗时100-Make The String Great
  • Android Studio中文界面汉化:3分钟告别英文困扰,提升开发效率50%
  • [Python3高阶编程] - 异步编程深度学习指南二(补充1): 什么是 Barrier 原语 【异步!!!】
  • 终极离线绘图解决方案:draw.io桌面版完全使用指南
  • 超越节点分类:Graph Transformer在脑网络分析中还能做什么?从疾病识别到生物标记发现
  • 2026年 光固化纳米陶瓷防腐耐磨材料厂家推荐榜:光固纳米陶瓷化防腐片材/卷材/耐磨涂层/复合树脂纳米陶瓷,技术前沿与耐久性能深度解析 - 品牌企业推荐师(官方)