
我整了一份《408 数据结构核心代码模板整理》并做成了 PDF,方便大家保存、打印,或者在暑假复习时随时查阅。
(原创且免费公开)公众号后台回复:代码题
领取《408 数据结构核心代码模板整理》PDF
每年复习到数据结构代码题,总会出现两种极端。
一种是看到指针、链表、递归就头疼,干脆安慰自己: “代码题就十几分,不会也不影响上岸。”
另一种是刚学完线性表,就跑去力扣刷题,一天研究两三道中等题。折腾半个月,回头一看,王道书还停在第二章。
这两种学法都不太对。
我集中看了近 5 年关于 408 数据结构代码题的经验贴、讨论帖和部分评论区,发现真正考得不错的人,方法不一定完全相同,但有一个共同点:
他们没有把 408 代码题当成程序设计竞赛,而是把它当成一道“需要写出算法过程的专业课大题”。
这两个东西看起来很像,准备方式却差得很远。
一、先弄清楚:408 代码题到底在考什么
408 的算法题通常不是让你写一个能提交、能编译、能通过所有测试点的完整程序。
一般不需要写输入输出,不需要处理工程环境,也不要求把头文件、主函数、内存释放全补齐。
真正需要写的,往往是:
一个核心函数; 一段算法思想说明; 时间复杂度分析; 空间复杂度分析。
这也是为什么很多上岸经验都会强调:
408 需要的是“能把思路翻译成相对规范的 C 或 C++ 代码”,而不是熟练掌握各种竞赛技巧。
基础较弱的同学,至少要补到下面这个程度:
能看懂并写出循环、判断和数组操作; 知道函数怎么传参; 看得懂结构体; 能处理链表指针; 理解递归函数是怎么调用的。
再往后,才是数据结构本身。
如果连 p = p->next 为什么能让指针后移都不明白,就直接去背链表算法,最后大概率只会背下一串字符。
题目稍微换个问法,就不会了。
但也没必要先花一两个月,系统学完整本 C 语言。
对于只准备 408 初试的人来说,C 语言补到“够用”就可以了。
重点掌握:
结构体; 指针; 数组; 函数; 递归。
至于文件操作、复杂语法和工程项目,暂时都可以往后放。
二、第一轮不要把大量时间耗在代码大题上
不少经验贴都提到,第一轮复习数据结构时,代码题可以学,但不适合死磕。
原因很简单:
第一轮最重要的任务,是先建立数据结构的整体框架。
你需要先弄清楚:
顺序表和链表有什么区别; 栈和队列分别解决什么问题; 树的遍历为什么经常使用递归; 图的 BFS 和 DFS 分别在做什么; 各种排序算法的过程和复杂度是什么。
这些东西没有建立起来,代码题几乎不可能真正学会。
有些同学第一轮就同时看教材、看视频、做辅导书,还给每道算法题抄一遍完整答案。
结果是数据结构一门课学了很久,其他三科的进度全部被拖慢。
失败经验里反复出现的一个问题,就是:
资料开得太多,笔记做得太细,产生了“每天都在学”的感觉,实际上有效输出很少。
比较合适的第一轮做法是:
看完一章; 挑最基础、最典型的代码过一遍; 先看懂算法过程; 再尝试脱离答案,写出大致框架。
写不完整没有关系,但至少要知道:
每一句代码在做什么,为什么要这样写。
比如学单链表,第一轮至少要会:
遍历链表; 查找结点; 插入和删除; 头插法、尾插法; 链表逆置。
学二叉树,至少要理解:
先序、中序、后序递归遍历; 层序遍历为什么需要队列; 如何统计结点数、高度或叶子结点数。
这些基本操作不只是“要背的模板”,更是后面真题进行组合和变形的零件。
第一轮的目标,不是看到一道陌生算法题就能马上写出最优解。
更现实的目标是:
看到答案时能够看懂,合上书后能够写出七八成。
三、真正有效的顺序,不是“看答案—背答案”,而是这四步
很多人学代码题的过程是这样的:
看题,不会。 看答案,觉得懂了。 抄一遍,感觉会了。 过几天再做,还是不会。
问题就出在“觉得懂了”。
看懂别人的代码,只代表你的阅读没有障碍,不代表你能独立产生这段代码。
我比较认同的练法,可以总结成四步。
第一步:先用人话说思路
先在脑子里想想思路,别急着写代码。
拿到题目后,先想清楚下面几个问题:
数据放在哪里? 我要遍历几次? 需要几个指针或辅助变量? 每一步到底在改什么? 有哪些特殊情况需要处理?
比如题目要求:
删除单链表中所有值为
x的结点。
不要一上来就背代码。
先用自己的话把过程说清楚:
从头开始遍历; 如果当前结点的下一个结点值为 x,就让当前结点跨过它;删除后,当前指针不能立刻后移; 因为新的后继结点仍然可能等于 x;如果不等于 x,当前指针再向后移动。
当这几句话能顺利说出来时,代码其实已经完成了一半。
能把算法过程讲明白,才有可能把它写明白。
数据结构里很多题,都适合自己画图。
特别是:
链表指针变化; 树的递归过程; 栈和队列的入栈、出栈; 图的遍历顺序。
画图和手动模拟,通常比死记一段代码更接近真正的理解。
第二步:先写一个能做出来的解法
考场高压环境下,不要一开始就逼自己想到最优算法。
408 的题目虽然经常要求:
“时间上尽可能高效。”
但考场上最怕的,不是复杂度差一点,而是十分钟过去了,答题纸上还是空的。
练习时可以先写朴素解法,再考虑怎么优化。
例如:
两层循环能解决,就先把两层循环写对; 需要额外数组,就先写额外数组; 需要多遍历一次,就先保证整体逻辑正确。
先确保算法能够完成任务,再考虑:
能不能减少遍历次数; 能不能降低时间复杂度; 能不能压缩辅助空间。
这几年,“暴力解 408 算法题”的内容很受欢迎,背后确实有现实原因:
一个正确、完整、能说明复杂度的朴素算法,通常比一段思路高级但漏洞很多的代码更有价值。
但要注意:
暴力解是一条保底路线,不是万能口诀。
暴力解本质上通常是枚举。
如果题目:
明确限制空间; 要求较高的时间效率; 或者朴素做法明显无法满足条件;
那你仍然需要掌握:
快慢指针; 双指针; 哈希; 递归; 分治; 辅助数组; 排序后处理。
所以更准确的策略是:
平时训练时,朴素解和最优解都要会;考场上实在想不到最优解,也要先保证有东西可写。
第三步:把代码放进编译器里验证
408 最终是手写,但前期不要拒绝编译器(请注意,是在前期时间充足的情况下)。
很多初学者手写代码时,自认为逻辑没有问题,实际一运行,错误一大堆:
指针没有初始化; 循环条件少写了等号; 删除结点后还在访问原地址; 数组越界; 递归缺少出口; 变量更新顺序写反; 链表断掉后找不到后续结点。
把代码放进编译器运行,可以迅速暴露这些问题。
你以为写对了,和它真的能处理各种情况,不是一回事。
前期可以在电脑上写,适当设计几个测试样例,例如:
空表; 只有一个结点; 所有元素都相同; 删除的是第一个元素; 删除的是最后一个元素; 目标元素连续出现。
等基本语法稳定后,再逐渐转到纸上。
第四步:一定要回到纸上默写
只在电脑上写也不行。
IDE 会帮你:
自动补全括号; 提示变量名; 标红语法错误; 自动缩进; 甚至直接给出代码片段。
但考试时,这些都没有。
所以到了强化阶段,一定要专门练纸笔。
比较实用的方式是:
每学完一类题,选两三道典型题,隔一天在白纸上重新写一遍。
写完后对照答案,不只看结果对不对,还要检查:
变量有没有定义; 指针含义是否清楚; 循环边界是否正确(其实考试不严格要求); 是否处理空表; 是否处理单结点; 是否处理长度为 1 的情况; 时间复杂度有没有写; 空间复杂度有没有写。
基本算法最好做到:
能够手写、能够手推、能够自己模拟运行过程。
较难的算法不一定要逐行背下来,但必须理解实现过程。
这个标准,比“把整本代码全部背下来”靠谱得多。
四、到底要不要背模板?
答案是:
要背,但不能只背。
数据结构代码题确实存在一批高频骨架:
数组遍历; 链表的插入、删除、逆置、合并; 快慢指针找中点; 双指针从两端处理; 栈和队列的基本操作; 二叉树递归遍历; 二叉树层序遍历; 图的 DFS 和 BFS; 常见排序过程; 二分查找。
这些内容如果每次都从零推导,考试时间肯定不够。
所以,必须熟练到能够快速写出来。
但“背模板”不等于逐字背答案。
真正值得背的是:
函数参数怎么设计; 指针或下标分别表示什么; 循环不变量是什么; 什么时候移动指针; 什么时候修改链接关系; 递归函数的结束条件是什么。
比如链表逆置,与其死背十行代码,不如记住三个角色:
pre:保存已经逆置好的部分;p:指向当前需要处理的结点;r:提前保存后继,防止断链后找不到剩余链表。
只要这三个指针的意义懂了,即使变量名换掉、题目包装换掉,你照样能写。
真正要记住的不是代码长什么样,而是每个变量承担什么任务。
如果只记代码外形,不理解变量作用,一紧张就容易出现这种问题:
“这一行到底应该放在指针后移之前,还是后移之后?”
五、要不要刷力扣?答案不是简单的“要”或“不要”
这是经验贴里争议最大的一点。
一部分上岸考生认为:
408 代码题只需要掌握辅导书里的经典算法,再认真做历年真题,不必专门刷大量 LeetCode。
这个观点有道理。
因为力扣更侧重:
算法应用; 在线判题; 完整代码实现; 边界测试; 某些技巧型解法。
而 408 除了代码大题,还有大量:
概念题; 性质题; 计算题; 综合应用题。
力扣不能覆盖数据结构专业课的全部要求。
而且,其中不少动态规划、回溯、复杂技巧,并不属于 408 的复习重点。
如果投入过多时间,大量刷题很容易挤占其他科目的复习时间,
但另一部分人的意见也不是错的。
对于代码基础很弱、经常出现“思路懂,但就是写不出来”的同学,适量做简单题确实有帮助。
在线判题可以帮你:
发现边界问题; 纠正语法错误; 训练函数实现; 把自然语言思路转化成代码。
所以,更合理的结论是:
下面几类人,不需要专门刷大量力扣
本科期间写过不少代码; 基本数组、链表和树题能够独立实现; 历年真题大部分能写出思路; 复习时间紧; 数学或其他科目还有明显短板。
这类同学以以下内容为主,基本就够了:
王道或天勤或竟成或其他教辅里的经典代码; 历年真题; 自己整理的专题题目; 纸笔手写训练。
下面几类人,可以适量刷简单题
跨考或几乎零代码基础; 知道算法思路,却经常写不出循环和递归; 链表、树的指针操作总是出错; 还需要兼顾复试机试。
刷题范围不要无限扩大,围绕 408 考纲即可:
数组; 字符串; 链表; 栈; 队列; 二叉树; 图的遍历; 查找; 基础排序。
难度建议:
以简单题为主,少量中等题即可。
不要为了一个和初试关系不大的技巧题,耗掉一整个下午。
六、真题应该怎么用,才不算浪费
很多人把代码真题留到最后,觉得做早了,以后就没有题目可以模拟。
其实,代码题没有必要这样留。
历年真题数量有限,但它的价值不只是测试分数。
更重要的是:
帮助你认识 408 到底喜欢怎么考。
有些题考:
数组上的空间换时间; 链表拆分、逆置和重新连接; 树的遍历与判断、统计、查找; 复杂度限制下的算法设计; 多个基本操作的组合。
真题至少可以分三轮使用。
第一轮:只做题型识别
看完题后,先判断:
考的是什么数据结构; 可能需要哪些经典操作; 朴素解是什么; 优化方向是什么。
写不完整没有关系。
这一轮的重点是:
建立题型和方法之间的联系。
第二轮:完整手写
这一轮要完整写出:
算法思想; 核心代码; 时间复杂度; 空间复杂度。
做完不要只对最终代码,还要关注:
哪些步骤是核心评分点; 哪些错误只会扣部分分; 哪些地方会导致整体逻辑失效; 朴素解和最优解的差距在哪里。
要逐渐建立一个认识:
一道代码题,并不是只有“全对”和“零分”两种结果。
第三轮:限时和复盘
考前可以把真题按类型打乱,不再按照年份或章节做。
每道题先限制思考时间。
到时间还想不到最优解,就练习:
写出合理的朴素方案; 把已经想到的步骤规范表达出来; 写清楚时间复杂度和空间复杂度; 尽量保住能够拿到的过程分。
复盘时,不要只记一句“这道题错了”。
要进一步标记错因:
没看懂题意; 数据结构选错; 算法思想没想到; 思路对,但写不出来; 边界遗漏; 指针更新顺序错误; 复杂度判断错误。
不同错因,解决办法完全不同。
复盘不是记住答案,而是找到自己为什么写不出来。
七、最值得整理的不是“万能模板”,而是自己的错题代码本
代码题笔记不要抄得太厚。
真正有用的内容,可以分成四类。
第一类:基础模板
例如:
链表操作; 树的遍历; 图的遍历; 排序; 查找; 栈和队列的基本操作。
第二类:常用算法思想
例如:
双指针; 快慢指针; 辅助数组; 哈希标记; 递归; 分治; 先排序再处理; 空间换时间。
第三类:自己经常犯的错误
例如:
链表断链; 数组越界; 递归没有出口; 删除结点后继续访问原地址; 指针移动过早; 循环边界少写一个等号。
第四类:真题中的组合方式
例如:
找中点 + 逆置 + 交叉合并
不要只把它记成一道孤立的题。
要拆成几个能够重复使用的基本操作。
比如一道链表重排题,可以拆成:
快慢指针找中点; 后半段原地逆置; 两段链表交替合并。
这种拆法,比死背完整答案更有迁移价值。
以后再遇到:
链表重排; 回文判断; 折半处理; 两段链表交叉操作;
就有可能复用其中的一两步。
不要只记“这道题怎么做”,要记“这道题由哪些基本操作拼出来”。
八、一个相对稳妥的训练安排
如果现在还在基础阶段,可以按照下面的节奏来。
基础阶段
重点是:
看懂数据结构和基本代码。
每章学习完,写 3~5 个最核心的基础操作。
不追求难题,也不追求第一次就写得完全正确。
强化前期
开始按专题练习:
数组和顺序表; 链表; 栈和队列; 树; 图; 查找; 排序。
每道题按照这个顺序练:
先说思路 → 再写代码 → 最后放进编译器验证。
强化后期
集中做历年真题。
同一道题最好经历下面几个步骤:
独立思考 → 参考答案 → 重新手写 → 隔几天再写
真正的掌握,不是当天看懂。
而是隔几天以后,没有答案,你还能写出来。
冲刺阶段
减少新题,增加:
纸笔默写; 限时训练; 错题复盘; 高频模板回顾; 真题组合方式整理。
每天不用写很多,保持手感即可。
重点复习自己反复出错的地方,而不是继续盲目扩充题量。
九、最后说几个很容易踩的坑
1. 不要无限收集资料
代码题资料永远找不完。
王道课后题、真题、专题题单和大量网课一起开,结果通常不是学得更全面,而是每套资料都只做了一点。
选一套主线资料,再用真题检验,已经足够。
2. 不要把抄代码当成练代码
抄得再工整,也不能证明你会写。
至少要有一次:
合上答案,从空白开始。
3. 不要每道题都追求最优解
理解最优解很重要,但考试首先要有得分能力。
先写对,再优化。
4. 不要只练电脑,不练纸笔
考试没有自动补全,也不会提示你少写了一个括号。
电脑负责发现错误,纸笔负责适应考试。
两种训练都需要。
5. 不要因为一道题卡住,就否定自己的代码能力
408 算法题本来就不是看两遍答案就能掌握的内容。
真正的学习过程往往是:
完全不会 → 能看懂 → 能复述 → 能模仿 → 能独立写
中间反复忘、反复错,都很正常。
写在最后
408 数据结构代码题真正需要的,不是刷几百道算法题,也不是背下一本代码答案。
更重要的是:
把有限的经典操作练熟; 把真题中常见的组合方式看懂; 能在没有编译器的情况下,把自己的思路写成阅卷老师看得明白的代码。
基础差,就先补 C 语言和基本操作。
思路有但写不出,就多做“口述思路到代码”的转换。
代码能写但容易错,就用编译器检查,再回到纸上默写。
冲刺阶段想不到最优解,也不要空着,先把正确的朴素方案和复杂度写出来。
代码题不需要神化,也不能完全放弃。
稳稳地把基础操作、真题和手写能力练出来,这道题就不会像刚开始看上去那么吓人。

我整了一份《408 数据结构核心代码模板整理》并做成了 PDF,方便大家保存、打印,或者在暑假复习时随时查阅。
(原创且免费公开)公众号后台回复:代码题
领取《408 数据结构核心代码模板整理》PDF
夜雨聆风