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

算法题解:单链表的高效实现(含经典致命错误深度剖析)

算法题解:单链表的高效实现(含经典致命错误深度剖析)

本文对应AcWing 826. 单链表,是链表入门的必做经典题。本文不仅会给出完整可运行的代码,还会深度拆解90%初学者都会踩的致命坑,帮你彻底搞懂链表的指针操作逻辑。

一、题目描述

实现一个初始为空的单链表,支持以下三种操作:

  1. H x:向链表头插入一个数x
  2. D k:删除第 k 个插入的数后面的一个数(当k=0时,表示删除头结点)
  3. I k x:在第 k 个插入的数后面插入一个数xk恒大于0)

进行完M次操作后,从头到尾输出整个链表。

⚠️核心注意点:题目中"第 k 个插入的数"≠"当前链表的第 k 个数"。它指的是按照插入时间顺序编号的节点,即使某个节点被删除了,后续节点的编号也不会改变。

数据范围1 ≤ M ≤ 100000

二、解题核心思路

2.1 为什么不能用普通指针遍历?

如果每次执行D kI k x操作时,都从头遍历链表找到第 k 个节点,那么单次操作的时间复杂度是O(n),总时间复杂度会达到O(n²)。对于M=1e5的数据量,这种写法会直接超时。

2.2 最优解法:数组映射法

我们用一个全局数组来记录每个插入节点的指针,数组下标就是节点的插入编号。这样我们就能在O(1)时间内找到任意一个历史插入的节点,所有操作的总时间复杂度降为O(n)

  • sort[i]:存储第i个插入的节点的指针
  • sort_count:记录已经插入的节点总数,作为下一个节点的编号

三、代码实现与经典错误剖析

3.1 错误代码(90%初学者都会写错)

先看大家最容易写出的错误版本,重点关注del函数:

// 错误的del函数voiddel(intx){if(x==0){// 删除头结点(这部分是对的)node*tem=list.Head;list.Head=list.Head->next;deletetem;}else{node*tem=list.sort[x]->next;// 要删除的节点// ❌ 致命错误:修改了sort数组!list.sort[x]=tem->next;deletetem;}}
错误原因深度解析

sort数组的作用是记录历史插入节点的指针,它是一个只读的映射表,绝对不能修改!

我们要删除的是"第 x 个插入的节点后面的节点",正确的逻辑应该是:

让第 x 个节点的next指针,直接指向被删除节点的下一个节点

而不是把sort[x]本身改成被删除节点的下一个节点。这会导致后续所有引用sort[x]的操作都指向错误的节点,彻底破坏链表结构。


3.2 测试用例错误过程演示

用你提供的测试用例一步步看错误是如何发生的:

输入: 10 H 2 // 第1个插入:节点1(2) D 0 // 删除头结点(节点1) H 6 // 第2个插入:节点2(6) H 8 // 第3个插入:节点3(8) I 2 5 // 第4个插入:节点4(5),插在节点2后面 I 2 3 // 第5个插入:节点5(3),插在节点2后面 I 4 6 // 第6个插入:节点6(6),插在节点4后面 I 3 4 // 第7个插入:节点7(4),插在节点3后面 D 3 // 删除第3个插入的节点(节点3)后面的节点(节点7) I 3 6 // 第8个插入:节点8(6),插在节点3后面

错误代码执行到D 3

  • 本来应该执行:节点3->next = 节点7->next(也就是NULL
  • 但错误代码执行了:sort[3] = 节点7->next(也就是NULL

后续执行I 3 6

  • 代码会尝试在sort[3](现在是NULL)后面插入节点8,这本来应该崩溃
  • 但由于内存未初始化等原因,实际会出现不可预期的行为,最终导致输出错误

3.3 修正后的完整可运行代码

#include<stdio.h>// 链表节点结构体structnode{intvalue;// 节点存储的值node*next;// 指向下一个节点的指针};// 链表整体结构体structLinkedList{node*Head;// 链表头指针node*sort[100005];// 映射表:sort[i] = 第i个插入的节点的指针intsort_count;// 已插入节点的总数};LinkedList list;// 全局链表实例(避免栈溢出)// 初始化链表voidinit_list(){list.Head=NULL;list.sort_count=0;}// 头插法:在链表头部插入值为x的节点voidhead(intx){node*new_node=newnode{x,NULL};new_node->next=list.Head;list.Head=new_node;// 记录新节点的插入顺序list.sort[++list.sort_count]=new_node;}// 删除第x个插入的节点后面的节点voiddel(intx){if(x==0){// 删除头结点node*tem=list.Head;list.Head=list.Head->next;deletetem;}else{node*pre=list.sort[x];// 前一个节点node*del_node=pre->next;// 要删除的节点// ✅ 正确写法:修改前一个节点的next指针pre->next=del_node->next;deletedel_node;}}// 在第x个插入的节点后面插入值为y的节点voidinsert(intx,inty){node*new_node=newnode{y,NULL};node*pre=list.sort[x];// 找到前一个节点// 标准链表插入操作new_node->next=pre->next;pre->next=new_node;// 记录新节点的插入顺序list.sort[++list.sort_count]=new_node;}intmain(){intm;scanf("%d",&m);init_list();for(inti=0;i<m;i++){charop;scanf(" %c",&op);// 前面的空格用于吸收换行符switch(op){case'H':{intx;scanf("%d",&x);head(x);break;}case'D':{intx;scanf("%d",&x);del(x);break;}case'I':{intx,y;scanf("%d %d",&x,&y);insert(x,y);break;}}}// 遍历输出链表node*cur=list.Head;while(cur!=NULL){printf("%d ",cur->value);cur=cur->next;}return0;}

3.4 测试结果

输入上述测试用例,输出结果为:

8 6 6 3 5 6

与标准答案完全一致。

四、关键知识点总结

  1. 数组映射法是处理"第k个插入节点"问题的标准解法,时间复杂度最优
  2. sort数组是只读的,只能用来记录节点指针,绝对不能修改它的值
  3. 链表删除操作的本质是:修改前一个节点的next指针,让它跳过被删除的节点
  4. 全局变量分配在静态存储区,不会出现栈溢出问题,适合存储大数组
  5. 题目保证所有操作合法,因此可以省略一些空指针判断,提高运行效率

五、拓展思考

  • 如果题目要求支持"删除第k个插入的节点本身",代码应该怎么修改?
  • 这种用数组模拟链表的方式,和用std::list相比有什么优缺点?
  • 如果需要支持双向链表的操作,这个思路还能用吗?

如果这篇博客对你有帮助,欢迎点赞收藏关注,有任何问题都可以在评论区留言交流~

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

相关文章:

  • Hypnos-i1-8B镜像免配置:开箱即用的8B推理环境(GGUF+Safetensors)
  • 2026年公司地址变更指南:这五份资料缺一不可
  • real-anime-z实战教程:用‘电影感构图+高度细节’生成专业级动漫封面
  • 5个关键步骤:在Windows 10上完美部署Android子系统的完整实战指南
  • 阿里中文语音识别模型实测:Speech Seaco Paraformer一键部署,会议录音秒转文字
  • 2026年质量好的广东汽车电磁阀/AMT电磁阀/汽车电磁阀多家厂家对比分析 - 行业平台推荐
  • 重磅发布 |智能体版知识库正式上线!邀您免费试用与专属定制
  • R 4.5低代码分析平台构建全链路(仅限首批内测开发者掌握的7大底层API调用逻辑)
  • Nginx SSL证书配置:从.pem到.crt,别再被‘BIO_new_file() failed’卡住了
  • 2026邯郸市佳铭文化:十年媒体沉淀,GEO优化口碑领航
  • 年轻人扎堆注销,三年少1.11亿张、45款被停发!信用卡撑不住了?
  • YOLO11涨点优化:注意力魔改 | A2-Net双重注意力模块引入,将特征聚合与分布完美融合,助力高精度检测
  • G-Helper终极指南:如何免费释放华硕ROG笔记本的全部性能潜力
  • 【仅限前200名开发者】EF Core 10向量搜索预编译插件(v10.0.1-rc3)免编译直装版泄露下载链接,含SQL Server 2022向量函数自动映射支持
  • 暴雪胜诉禁令致《魔兽世界》Turtle WoW经典服务器宣布关闭
  • 在线客服系统正在被重写:AI智能客服工具如何改变服务逻辑
  • 【Dify金融问答合规配置黄金法则】:20年监管科技专家亲授3大避坑指南与5步落地 checklist
  • nli-MiniLM2-L6-H768保姆级教学:Web UI汉化、主题定制与企业内网安全加固
  • 【Dify多租户数据隔离实战白皮书】:20年架构师亲授4层隔离防线设计与生产级避坑指南
  • Qwen3-4B-Thinking效果展示:编程错误诊断+修复建议生成真实案例
  • 墨语灵犀效果对比评测:AI翻译中‘文气’‘留白’‘韵律’三大维度拆解
  • DeepSeek V4 :长期记忆 + 编程能力双突破,国产大模型的护城河在哪?
  • Vivado 2019.1实战:用Floating-Point IP核搞定CORDIC输出的定点数转浮点数(附完整代码)
  • Chart.js 4 中实现基于数据实际范围的垂直线性渐变
  • 告别Winform土味界面!用MaterialSkin让你的C#桌面应用秒变Material Design风格
  • 新概念英语第二册17_Always young
  • 游戏版本,数据被盗如何预防
  • Dify企业版权限配置紧急响应手册:当API密钥泄露、成员越权访问、审计日志缺失时,5分钟完成熔断+溯源+加固
  • real-anime-z GPU利用率监控教程:nvidia-smi+Prometheus可视化看板
  • 成都缠绕膜与胶带厂家对比分析:产能、性能与采购建议