news 2026/9/7 3:50:03

哈工大数据结构44讲:从线性表到图,训练复杂度权衡与算法直觉

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
哈工大数据结构44讲:从线性表到图,训练复杂度权衡与算法直觉

看到“哈尔滨工业大学《数据结构》全44讲|线性表、树、图、查找与排序”这个标题,很多人的第一反应是赶紧保存课件视频、找到配套的严蔚敏《数据结构(C语言版)》电子书,然后从第1讲开始倍速刷到第44讲。这个做法不能说错,但大概率会在第5讲左右放弃,因为线性表部分看起来太“基础”,越到后面越容易觉得抽象。

我更愿意把44讲当成一条完整的训练路线来看。它真正要解决的问题,不是让你背会“什么是线性表”“什么是二叉树”,而是训练你形成一种反应:面对一个问题时,能先判断数据之间的关系长什么样,再决定用什么结构存储,最后用算法把时间复杂度和空间复杂度控制在可接受的范围内。这种反应,才是数据结构这门课真正想留给你的东西。下面我会顺着44讲的展开顺序,把每一块内容拆开,讲清楚它们之间的递进关系、日常落地时最常踩的坑,以及学完这套课之后,你还需要补什么。

1. 先把44讲的整体逻辑看懂,才知道每节课在解决什么问题

1.1 课程顺序不是按目录抄的,而是一条“数据关系复杂度”的递进线

如果你只看哈工大《数据结构》全44讲的章节目录,可能会觉得它跟市面上的数据结构教材差不多:先是线性表,再是栈和队列,然后是树、图,最后是查找和排序。这个顺序看起来像约定俗成,其实背后有一条很清晰的认知逻辑。

线性表解决的是“一列数据怎么存”的问题。生活中的排队、通讯录、历史记录,本质上都是线性关系。树解决的是“一对多”的问题,比如公司组织架构、文件目录、分类导航。图解决的是“多对多”的问题,比如城市交通、社交网络、依赖关系。从一维到二维,从层次到网络,这是数据关系复杂度的不断升级。

每个阶段的结构都在上一阶段的基础上增加新的约束或新的可能性。比如树可以理解为“多个线性表在纵向上的组合”,图又可以理解为“树去掉了父子层级限制后的推广”。如果理解了这条递进线,你就不会把每节课当成孤立知识点去背,而是会自然地想到:这种新的数据结构,是在解决上一类结构表达不了什么问题?

1.2 44讲真正想训练的不是“记忆”,而是两种直觉

第一种直觉是数据形状直觉。看到一个问题,你能快速判断它是线性问题、层级问题还是网状问题。比如设计一个文件系统,目录天然是树形;设计一个社交好友关系,天然是图;设计一个交易流水表,天然是线性表。这个判断通常在写代码之前就已经完成了。

第二种直觉是复杂度权衡直觉。同一个问题往往有多种数据结构可以用,但每种都有自己的代价。数组支持随机访问,但插入删除要搬移元素;链表插入删除灵活,但访问第k个元素要遍历。你需要在时间和空间之间做选择,甚至需要在“实现复杂度”和“运行效率”之间做妥协。

44讲看起来是在讲“结构”,其实是在用大量例子逼你在不同结构之间反复比较。如果你只是把代码抄了一遍,却没有总结“这个结构为什么在这个场景下比那个结构好”,那这门课的价值就只发挥了一半。

1.3 这门课和经典教材的关系怎么理解

很多人在学习时会配套严蔚敏《数据结构(C语言版)》,这本书的代码示例偏教学化,很多函数都用“抽象数据类型”的方式包裹起来。哈工大这套44讲课程在整体知识框架上与经典教材一致,但你在实际落地时要注意一点:课程里的伪代码和教学代码,不能直接照搬到生产项目里。

原因很直接:教学代码追求的是“把原理讲清楚”,所以会突出核心逻辑,省略参数校验、内存释放、并发保护、边界判断。真实项目中,一个链表插入函数可能需要同时处理空链表、尾节点、内存分配失败、多线程竞争等一堆情况。这不是课程讲得不好,而是教学和生产本来就有不同的目标。学的时候跟着课程写,用的时候要额外补工程化能力。

2. 线性表部分:看着最简单,其实藏着最关键的取舍训练

2.1 顺序表和链表的争论,本质是“访问快”和“修改快”的取舍

线性表最先讲顺序表和链表,很多初学者容易陷入一个误区:总想分个高下,觉得链表比数组高级,或者觉得数组更简单。

实际上,这两种结构解决的问题完全不同。顺序表(数组)的核心优势是随机访问,通过下标直接定位,时间复杂度是O(1);链表的优势是插入删除,只需要修改指针,时间复杂度O(1),但查找需要O(n)。真实场景里,你几乎不会遇到一个程序只需要“插入删除”或只需要“随机访问”的情况,大多数时候是混合的。

我建议你学这部分时,不要只背“数组插入O(n),链表插入O(1)”这种结论,而是去追踪一下背后的数据搬移过程。数组为什么插入慢?因为它要腾位置,后面的元素统统往后移。链表为什么随机访问慢?因为它不能直接跳转,只能顺着next一个个找。理解了这两条底层机制,你就不会再犯“哪种更好”这种错误提问。

2.2 栈和队列:不是简单的“特殊线性表”,而是两种流程控制模型

讲到栈和队列时,课里会说它们是“操作受限的线性表”。这个词容易让人低估它们。实际上,栈和队列代表了两种极其重要的处理顺序:后进先出先进先出

栈解决的是“需要回退”的问题。函数调用要保存返回地址,所以要用栈;浏览器要记录历史,所以要用栈;表达式求值里中缀转后缀,也要用栈。你只要记住一句话:凡是“最近发生的优先处理”的场景,大概率要用栈。

队列解决的是“需要按顺序处理”的问题。消息队列在先进先出的基础上削峰填谷;任务调度按顺序执行;打印机任务排队;CTF题目里的广度优先搜索也依赖队列。如果你在代码里发现某个逻辑是“先到先处理”,队列就是最直接的结构。

这里有个很实际的建议:学栈和队列时,不要只练教科书上的“括号匹配”和“迷宫寻路”,可以把它们放到真实场景里想一遍。比如,当你第一次接触前端路由的回退、后端任务队列、操作系统中断处理时,能立刻意识到“这是栈,这是队列”,比刷十道题都有用。

2.3 字符串、数组和广义表:它们不显眼,但决定了你能走多远

线性表里还包含字符串、数组和广义表。很多初学者觉得字符串就是char数组,没什么好学的,结果到做文本处理、写正则、做压缩算法时才发现,底层全是串的模式匹配问题。

这一块真正有价值的内容是经典算法背后的暴力思想进阶。比如KMP算法,表面上是一个匹配算法,实际上是“在匹配失败时,利用已知信息跳过无用比较”的思路。这类思想在后面很多地方都会出现:缓存、动态规划、AC自动机,本质上都在做“避免重复计算”。

数组部分看起来更基础,但多维数组的存储地址计算、稀疏矩阵的压缩存储,这些内容能帮你建立“空间是连续的,访问要算偏移”的意识。如果你未来要接触图像处理、矩阵运算、深度学习框架,这些基础反而是最扎实的地基。

3. 树和图:从“一对多”到“多对多”,是一次思维方式跃迁

3.1 树的核心价值,是“把查找的问题变成路径的问题”

树结构最基础的是二叉树,往上还有平衡二叉树、B树、红黑树、哈夫曼树、字典树等。你可以把它们看成一个家族,但它们要解决的问题不太一样。

普通二叉树帮你建立递归思维:左子树、右子树、前序、中序、后序。平衡二叉树和红黑树解决的是“别让树退化成一个链表”,保证查找效率稳定。B树解决的是“磁盘读写代价高,尽量减少IO次数”,所以数据库索引爱用它。哈夫曼树解决的是“怎么用最短的编码表示一批字符”,压缩算法依赖它。字典树解决的是“多个字符串之间的公共前缀怎么复用”,搜索引擎提醒和敏感词过滤里会用到。

这些树看起来各有各的复杂规则,但底层都是同一件事:通过改变数据的组织方式,让查找路径变短。你在学习时不要被旋转、变色、分裂这些操作吓到,先问自己一句:为什么要付出这些维护成本?因为不维护,树就会失衡,查找路径就会变长。有了这个目标,再看那些复杂的调整操作,你会觉得每一步都有明确目的。

3.2 图的遍历是理解“关系网络”的入口

图这一章,很多新手会觉得概念特别多:有向图、无向图、带权图、邻接矩阵、邻接表、深度优先遍历、广度优先遍历、最小生成树、最短路径。其实真正要抓住的就两条主线:怎么存储图怎么遍历图

存储方式上,邻接矩阵适合稠密图,判断两点之间是否有边很快,但浪费空间;邻接表适合稀疏图,只存存在的边,空间利用更好。这个选择本身就是一次典型的空间复杂度权衡。

遍历方式上,深度优先和广度优先的区别,本质上和栈、队列的区别一脉相承。DFS用一个栈(递归也是栈)深入到底,适合走迷宫、寻找所有路径、拓扑排序;BFS用一个队列层层推进,适合找无权图的短路径、判断几度好友、爬虫里的层级抓取。学到这里你会发现,前面线性表里栈和队列的那套知识,开始真正派上用场了。

3.3 树和图的“实现”要比“概念”重要得多

很多学生能说出红黑树的五个性质,能画出平衡二叉树的旋转过程,但一让他写一个二叉搜索树的删除操作,就开始漏边界。这是因为树的实现里充满了递归和指针操作,每一层递归都要保证返回值和结构正确性。

我强烈建议学树和图时,至少完整跑通这几个代码:

  • 二叉树的前序/中序/后序遍历(递归和非递归各写一遍)
  • 二叉搜索树的插入、查找、删除
  • 图的标准BFS和DFS遍历
  • 用邻接表存图,再实现一个带权最短路径算法

不要只在草稿纸上画过程,要真的把代码写出来,用带断点的调试器一行一行走。图形结构和线性结构最大的不同是“分支多、路径多”,一遍跑通很可能只是运气,多试几个边界输入才能真正暴露问题。

4. 查找与排序:不是在学算法,而是在学“如何衡量一个方案的代价”

4.1 排序算法不是背时间复杂度表,而是理解每一种排序在做什么维度的妥协

排序这章通常包括插入排序、冒泡排序、简单选择排序、希尔排序、快速排序、堆排序、归并排序等。初学者很喜欢背一个复杂度表:快速排序平均O(n log n),插入排序O(n²),归并排序稳定……背完合上笔记就问“出自哪里在哪”的也大有人在。

问题在于,这些复杂度结论背后是不同的动机。插入排序在小规模数据上比快排还快,因为常数小;归并排序稳定,但需要额外空间;快速排序平均快,但最坏情况会退化到O(n²);堆排序不需要额外空间,但局部性较差,实际速度反而不如快排。真实项目里,你选的往往不是“理论最优”的算法,而是对你场景最合适的算法。

一个稳妥的思路是:排序练习不要只做“用代码实现一遍”。把每两种排序放在同一份数据上,对比比较次数、交换次数、运行时间;想清楚哪些排序是稳定的,哪些不稳定,为什么不稳定;了解哪些排序适合链表,哪些适合数组。这些具体差异,比背一张表有用得多。

4.2 查找算法的本质,是把“一次猜很多次”变成“每次排除一半”

查找部分除了顺序查找,最重要的就是二分查找和哈希查找。

二分查找的前提是有序数据,它的思想是:每次比较后排除一半不可能区间。这个思想简单到很多人觉得没什么好学的,但真实写代码时边界条件很容易错。左闭右开,还是左闭右闭?mid取上整还是下整?循环条件是left<right还是left<=right?边界差一位就是死循环或越界。

哈希查找则是另一种思路:不是缩小范围,而是通过函数直接定位。哈希表的关键不在“查找快”,而在“冲突怎么解决”。拉链法怎么设计?开放定址法什么时候退化?负载因子为什么重要?这些问题直接关系到一个系统在数据量扩大后会不会明显变慢。

4.3 查找排序是前面所有数据结构的“验收场景”

你会发现,查找和排序并不是独立的知识,而是所有数据结构都要用到的通用工具。树要有搜索树功能,图要找路径,线性表要排序查找,字符串要模式匹配。所以这一章放在最后是有道理的:它是在检验你对前面所有结构的掌握程度。

比较好的学习方式是:学完一章,就回到“查找和排序”这个目标去反问自己。比如学了二叉树,就问“为什么二叉搜索树的查找很快,但普通链表不行”;学了哈希表,就问“为什么哈希表的平均查找效率是O(1),但最坏情况会退化”;学了图,就问“最短路径问题和最小生成树问题为什么不能用同一个算法”。这样的反问,会把分散的知识织成一张网。

5. 实际学习中最容易踩的坑,以及一套能长期用的落地流程

5.1 四个最常见的坑,越早避开越省时间

第一个坑是只看不写。数据结构不是看会的,是练出来的。指针指向哪里、递归什么时候返回、树的旋转怎么复位,这些细节只在写代码时才暴露出来。如果只是把课程视频从头看到尾,你会产生一种“我懂了”的错觉,真正上手时才发现什么都写不出来。

第二个坑是只写不调。有些学习者倒是肯写代码,但写完看结果不对,马上翻答案或者重写一遍,很少用调试器去看中间过程。数据结构代码出错,往往不是最后结果错,而是某个节点的指针指错了。你要学会在关键位置打断点,观察每一步执行后链表长什么样、树的结构对不对。这个过程虽然慢,但能帮你真正建立底层直觉。

第三个坑是跳过复杂度分析。很多人写一个功能,能跑通就满足了,完全不关心它在大数据量下会不会崩。数据结构的核心就是复杂度分析,如果只停留在“实现出来”,就失去了判断方案优劣的能力。面试和真实项目里,不是“能跑就行”,而是“跑了之后资源可控、时间可接受”。

第四个坑是过早深入偏门结构。红黑树、B树、跳表这些高级结构确实有热度,但如果连二叉搜索树都写不熟练,去学红黑树只会变成背规则。建议先把核心结构学扎实:线性表、栈队列、二叉树、图的基本遍历、二分查找、哈希表、快排归并堆排序。这些学透了,再往上走会顺很多。

5.2 一套可以从第1讲用到底的“四步法”

学完每一讲,或者学完一个数据结构模块,我建议按下面这个流程走一遍:

  1. 描述:不看课本,用三句话讲这个结构解决什么问题,适合什么场景,不适合什么场景。
  2. 实现:用C语言从头写一个最小实现,不要复制代码,从空文件开始写核心部分。
  3. 实验:造几组不同分布的数据,测试在正常情况、边界情况、极端规模下表现如何。
  4. 比较:把它和你已经学过的结构放在一起,列出各自的时间复杂度、空间复杂度和实现复杂度。

这套方法看起来慢,但长期效率很高。因为它把每一次学习都变成了“可复用的经验”,而不是“感觉学过了”。

5.3 遇到问题和报错时的排查顺序是什么

数据结构代码报错,很多人第一反应是改代码。但实际上更稳妥的顺序是:先确认问题的现象属于哪一类,再看输入数据是否正常,然后检查指针或索引是否越界,最后才考虑算法逻辑有没有写错。

比如链表插入后遍历死循环,大概率是指针没有正确回链;数组排序后结果不对,先看比较条件是不是写反了;二叉树递归栈溢出,先想递归终止条件是不是漏了;程序崩溃,先用调试工具看是哪一步访问了非法地址。排查时不要乱试,先复现,再缩小范围,最后修改验证。这个思路不仅在数据结构课上有用,以后做任何项目排查问题都通用。

6. 44讲学完之后,还需要补什么才能进入真实项目

6.1 工程化能力:存储从内存走向文件,从单线程走向高并发

课程里的数据结构和算法默认都在内存里运行,复杂度分析也大多基于“内存访问”。但真实系统里,数据往往放在磁盘、数据库、缓存服务器里,这时候需要考虑的就不再只是算法复杂度了,还有IO开销、序列化格式、并发一致性。

比如课程里讲哈希表,你知道了哈希函数和冲突解决。但生产环境里的Hash表还要考虑扩容时机、线程安全、内存占用上限。又比如图算法里讲最短路径,你知道了Dijkstra。但导航系统里动辄几百万个节点,还需要考虑预处理、分层图、A*这类启发式搜索。这些都不是44讲会全部覆盖的,需要你在做实际项目时逐步补充。

6.2 从C语言到其他语言:语法不同,但底层逻辑是相通的

哈工大这套课用的是C语言,好处是让你直面指针、内存和底层实现。但很多读者平时可能用Java、Python、Go写业务。你不用觉得“我不用C是不是白学了”,恰恰相反,如果你能在C语言里把链表和二叉树写明白,换到其他语言只是换了一层语法壳。

比如Python里你可以直接用listdictdeque,但你仍然需要知道背后的实现原理和复杂度;Java里你可以用ArrayListLinkedListHashMap,但什么时候选哪个,决定因素和C语言里学到的完全一样。数据结构课训练的是迁移能力,不是某个语言的API使用技巧。

6.3 课程之后可以再走三步

看完44讲后,你可以按下面三步继续进阶:

  1. 刷题巩固:找一套按数据结构分类的题目集,每天按模块刷。重点是刷完题之后总结规律,比如“什么题可以用栈辅助”“什么题是BFS的变体”“什么场景需要LRU缓存结构”。
  2. 看一门系统设计或数据库类课程:你会看到数据结构在真实系统里是怎么被用起来的,比如数据库索引是B+树,Redis里是跳表,消息队列是链表加哈希表。这个阶段能帮你把“数据结构课上学到的”和“生产系统里存在的”连起来。
  3. 在真实项目里做一次选型复盘:每次写涉及数据存储或搜索的代码时,刻意问自己一句“为什么用这个结构,不用另一个结构”,并在代码注释里写清楚。别嫌麻烦,写几次之后,数据结构的选型能力就会有明显提升。

6.4 适用边界:这门课适合谁,不适合谁

适合正在操作系统类专业课的本科生,适合准备考研或求职笔试需要系统复习的读者,也适合工作三五年后觉得“基础不够扎实”想回头补课的后端开发者。

不太适合完全没有编程经验的人直接从数据结构入手,因为你可能还没掌握语言基础,会卡在指针和递归上;也不适合只想快速刷题过面试的人,因为44讲更重视原理推导,节奏比短视频式刷题要慢很多。

如果你明确知道自己要参加算法面试,可以直接把这门课当复习主线,配合分类刷题,效率很高。如果只是感兴趣想了解“数据结构到底是什么”,也不用强迫自己从头到尾学完,先看前几讲建立概念,再挑树和图模块深入,会更友好。

44讲本身是完整的,只是你要清楚你的目标是什么。把它的知识变成你自己脑子里的数据形状直觉和复杂度权衡直觉,这门课才算真正学到位了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/7 3:49:48

从CubeAI到CubeAI Studio:嵌入式AI模型部署工具的进化与选型

如果你在STM32圈子里混过一阵子&#xff0c;大概率已经听过CubeAI这个缩写。它几乎是嵌入式AI落地的代名词&#xff1a;把电脑上训练好的神经网络模型&#xff0c;打包转换成能在STM32这种资源有限的MCU上跑起来的C代码。前两年大家遇到这个问题&#xff0c;第一反应都是打开ST…

作者头像 李华
网站建设 2026/9/7 3:46:27

从API 403到暂缓发布:AI安全如何重塑模型竞争逻辑

先从一个很具体的场景说起。这段时间在技术社区里&#xff0c;能看到不少开发者反馈 Anthropic API 连接异常&#xff0c;报错类似 "unable to connect to anthropic services: failed to connect to api.anthropic.com: status 403"。有人在排查自己的账号额度&…

作者头像 李华
网站建设 2026/9/7 3:46:20

内窥镜设备标准IEC 60601-2-18:2009解读与送检避坑指南

简介&#xff1a;IEC 60601-2-18:2009 是国际电工委员会发布的内窥镜设备专用安全标准&#xff0c;面向医疗设备研发、注册与检测人员&#xff0c;用于规范硬性、软性及纤维内窥镜的基本安全与主要性能要求。该标准在 IEC 60601-1 通用要求基础上&#xff0c;补充了电击防护、机…

作者头像 李华