拓扑排序失败首要原因是indegree数组未初始化为0或邻接表方向错误;必须用vector(n,0)初始化,确保每条边u→v执行graph[u].push_back(v)和indegree[v]++,BFS中每次--indegree[v]后立即检查是否为0才入队,最终以result.size()==n为环检测唯一标准。

拓扑排序失败,八成是 indegree 数组没初始化为 0,或者邻接表方向反了——不是算法逻辑难,而是这两处错一点,整个结果就全空或少节点,还查不出报错。
为什么 indegree 必须用 vector(n, 0) 初始化
裸数组如 int indegree[1000] 不 memset 就用,里面是随机值;vector 不带初始值也一样危险。一旦某个节点 indegree[i] 是负数或大整数,它永远进不了队列,哪怕它本该是起点。
- 孤立节点(无入边也无出边)必须靠
indegree[i] == 0被捕获,否则直接漏掉 - 输入边是 1-based?读入后立刻转成
u-1,v-1,别留到建图时再算 - 节点编号不连续(比如只有节点 2、5、9)?改用
unordered_map,但得先遍历所有边的u和v,把它们都插入 map 并初值设为 0
graph[u].push_back(v) 写反了会怎样
写成 graph[v].push_back(u),BFS 弹出 u 后,graph[u] 是空的,下游节点 v 的入度根本不会减,全部卡死。调试时打印 graph[0],确认里面存的是从 0 出发的终点,不是指向 0 的起点。
- 每条边
u → v只调一次graph[u].push_back(v)和indegree[v]++ - 别在循环里反复
push_back同一条边——重边要提前去重,或接受indegree[v]被加多次(那后续就得减多次才能归零) - 邻接表用
vector,别用> list或map,缓存不友好,小图看不出,大数据跑得慢
BFS 中更新 indegree[v] 的时机不能错
不是“先把所有邻居入队再统一减”,也不是“减完不管是不是 0”,而是每次 --indegree[v] 后**立刻**检查是否为 0,是才推入队列。漏掉这个 if,节点就永远沉底。
- 标准写法:
for (int v : graph[u]) { if (--indegree[v] == 0) q.push(v); } - 别写成先
indegree[v]--,再另起一行if (indegree[v] == 0)——中间可能被其他逻辑干扰 - 不要在入队前加
&& !visited[v]这类冗余判断,indegree[v] == 0就是唯一合法入队条件
怎么判断图里有环——别信队列空了
队列空了只说明当前没入度为 0 的节点可处理,不代表排完了。真正可靠的环检测,就看最后 result.size() != n。这个等式不成立,就是铁证有环,不用额外 DFS。
- 初始化
queue时,必须扫完整个节点范围(比如for (int i = 0; i ),把所有indegree[i] == 0的都推进去 - 返回值建议设为
vector,空容器表示有环;别用bool+ 输出参数,容易掩盖问题 - 最容易被跳过的点:节点总数
n是你从输入解析出来的,不是边列表长度,也不是max(u, v) + 1——题目说“共 n 个节点”,你就老实用那个 n
真正难的不是写对主干逻辑,而是确保 n 的来源、indegree 的覆盖范围、graph 的索引方向这三件事严丝合缝。漏一个,result.size() 就不准,环检测就失效。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











