算法概念速查
什么是拓扑排序?Kahn 算法、判环原理与经典例题
一句话定义
拓扑排序是把有向无环图(DAG)的所有节点排成一个线性顺序,使每条边都从排在前面的节点指向排在后面的节点——「先修课永远排在后修课前面」。标准做法是 Kahn 算法:反复取出入度为 0 的节点放进结果、并给它的后继减入度;如果最后取出的节点数少于总数,说明图中有环,根本不存在合法顺序。
先打个比方
像安排一学期的选课顺序:《数据结构》要先修《程序设计》,《算法》又要先修《数据结构》。每学期你只能选「先修课已全部修完」的课——这就是「入度为 0 才能入队」。如果两门课互为先修(成环),谁也别想开始,这学期就死锁了——这正是「有环则无拓扑序」。
它是怎么运作的
Kahn 算法四步:① 建邻接表并统计每个点的入度;② 所有入度为 0 的点入队;③ 出队一个点计入结果,它指向的每个后继入度减一,减到 0 就入队;④ 队列空后,比较「结果数 == 节点总数」——相等则输出拓扑序,少了则有环(环上节点的入度永远减不到 0,进不了队)。整体 O(V + E)。
建边方向是最高频的翻车点:prerequisites[i] = [b, a] 表示「修 b 之前要先修 a」,应建边 a → b、给 b 的入度加一。记牢口诀「先修指向后修」,方向反了整个顺序全错。
什么时候用:识别信号
题目里出现下面任何一条,就该想到「拓扑排序」。
- 题面出现「先修 / 依赖 / 前置任务 / 先后顺序」这类字眼
- 要判断一批带依赖的任务能否全部完成(= 有向图是否无环)
- 要输出一个满足所有依赖的合法执行顺序
- 要按依赖关系分层处理:一层做完才能做下一层
别和它们搞混
配套动画题:眼见为实
每道题都有逐步交互动画,看着数据动起来,比读十遍文字都快。
常见追问
拓扑序是唯一的吗?
一般不唯一:队列里同时有多个入度 0 的点时,先取谁都合法。只有每一步队列里恰好一个点,拓扑序才唯一——有些题会反过来考「判断顺序是否唯一」。
为什么队列空了不代表修完了所有课?
有环时环上的课入度永远大于 0、从不入队,队列会「提前」空掉。所以判断依据必须是「处理过的节点数是否等于总数」,直接返回 true 是经典 bug。
DFS 也能做拓扑排序吗?
能:对每个点做 DFS,节点「访问完成」时压入栈,最后整栈逆序弹出就是拓扑序;判环用三色标记(访问中再次遇到「访问中」的点即有环)。Kahn 更直观,DFS 版在需要后序信息时更顺手。