Kahn算法需先统计入度,因拓扑排序必须从入度为0的节点开始;若漏统计或更新错误,BFS将无法启动或失效,且最终结果节点数少于n即表明存在环。

为什么 Kahn 算法要先统计每个节点的入度
因为拓扑排序必须从「没有前驱」的节点开始,也就是入度为 0 的节点。如果跳过入度统计,BFS 阶段就无法判断哪些节点能作为起点,后续队列推进会直接失效。
实际中常见错误是只建了邻接表,却忘了同步维护 indegree 数组——比如用 vector 存图后,没初始化 indegree 为全 0,或遍历边时漏加 indegree[v]++,导致 BFS 一开始就卡住。
- 入度数组大小必须和节点编号范围一致(例如节点编号是
1~n,数组就得开n+1) - 若图含孤立节点(无边连入也无边连出),其入度为
0,仍需被加入初始队列 - 统计完务必检查:所有节点的入度值是否都已更新,尤其注意输入边时是否把方向弄反(把
u -> v误写成indegree[u]++)
如何用 queue 实现标准 BFS 流程而不漏节点
核心不是“遍历邻居”,而是“每弹出一个入度为 0 的节点,就把它所有后继的入度减 1;一旦某个后继入度降为 0,立刻入队”。这保证了依赖关系被逐层解开。
容易踩的坑是:在 for 循环里修改了 indegree[v] 后,忘记判断 if (indegree[v] == 0) 就直接 push,结果把入度还没清零的节点塞进队列,破坏顺序性。
- 必须在每次
indegree[v]--后紧跟if (indegree[v] == 0) q.push(v) - 使用
queue即可,无需优先队列——Kahn 本身不保证字典序,如需字典序最小拓扑序,得换priority_queue - 别在 BFS 过程中修改图结构(如删边),只改入度数组
怎么判断图中存在环(即拓扑排序不存在)
拓扑排序存在的充要条件是:有向图无环(DAG)。Kahn 算法天然具备检测能力——只要最终输出的节点数少于总节点数,就说明有环。
典型错误是只检查队列是否为空就退出,却不比对结果容器大小。例如 result.size() != n 时,应明确返回空 vector 或抛异常,而不是静默返回截断结果。
- 初始化时记录总节点数
n(不能只靠图的邻接表大小,因可能有未出现的孤立点) - 输出结果用
vector累积,而非边遍历边打印——否则无法统一判断是否成环 - 若输入含重复边,会导致同一
v被多次减入度,可能提前变成0,所以建图前建议去重或用set辅助
C++ 实现中 vector 和 queue 的边界细节
vector 下标访问、queue 的线程不安全、以及空队列调用 front() 都是运行时崩溃高发点。Kahn 算法虽逻辑简单,但这些细节一错就段错误。
例如:用 graph[u].size() == 0 判断是否还有后继,不如直接遍历 for (int v : graph[u]) 安全;又如没在 while 前判空就调 q.front(),会触发未定义行为。
- 声明
indegree时用vector,避免下标越界(n + 1, 0) - while 循环必须写成
while (!q.empty()),且每次循环开头用int u = q.front(); q.pop(); - 邻接表
graph类型推荐vector,不用> vector——后者迭代器写法易错,且无随机访问优势- >
拓扑序是否唯一、是否存在多解,不影响 Kahn 算法正确性;但如果你依赖输出顺序做后续计算,就得意识到:队列顺序(比如用 stack 替代 queue)会改变结果,而这种改变不是 bug,是算法自由度的一部分。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











