您的位置:首页 >C++拓扑排序判环方法详解
发布于2026-02-22 阅读(0)
扫一扫,手机访问
Kahn算法用std::queue和入度数组实现拓扑排序:建图时记录每条边u→v并统计indeg[v]++,初始化将所有indeg[i]==0的节点入队,每次出队一个点并对其邻接点减入度,减至0则入队;最终若加入拓扑序列的节点数cnt≠总节点数n,则存在环。

std::vector<std::vector<int>> 建图后怎么跑拓扑排序拓扑排序本质是判断 DAG(有向无环图)是否成立,核心动作就是「删入度为 0 的点,更新邻居入度,重复直到删完或卡住」。C++ 里最常用的是 Kahn 算法,依赖 std::queue 和入度数组。
常见错误现象:queue 为空但还有节点没访问到 → 说明存在环;或者漏初始化入度数组,导致未定义行为。
adj[u].push_back(v) 表示边 u → v,同时对每个 v 执行 indeg[v]++indeg 数组大小必须覆盖所有可能的节点编号(比如节点是 1~n,数组就要开 n+1,下标 0 不用也行)indeg[i] == 0 的 i 入队,哪怕 i 是孤立点(入度出度都为 0)也要算进拓扑序列indeg[v]--,减到 0 就立刻入队queue.empty()很多人写完 Kahn 就直接检查最后 queue 是否为空,这是错的——queue 只反映“当前可删的点”,不是“是否删完了”。真正判断环的依据是:最终加入拓扑序列的节点数是否等于总节点数。
使用场景:你传入了 n 个节点,但图里实际只出现过其中一部分编号(比如只有 0、2、4),这时要小心「未出现的节点是否该计入总数」。通常约定:输入明确给出节点范围 [0, n) 或 [1, n],就以 n 为准。
cnt,每弹出一个点就 cnt++cnt != n 就代表有环queue.size() == 0 && cnt < n 当判断条件——队列空是常态,不意味着结束std::stack 替换 std::queue 会影响环检测结果吗不影响。Kahn 算法中用栈还是队列,只改变拓扑序的输出顺序(DFS-like vs BFS-like),不改变「能否遍历全部节点」这个事实。环的存在性是图的固有属性,和遍历容器无关。
性能影响:栈在缓存局部性上略好,但差别微乎其微;兼容性无差异,都是标准容器。
std::stack,记得用 s.top()/s.pop(),别误用 front()std::priority_queue,但那是另一回事,和环检测无关visited 要分三种状态DFS 版本不生成拓扑序,只判环,但更贴近直觉:遇到正在递归中的节点,就说明成环。关键在于 visited 不能只是 bool,必须区分「未访问」「访问中」「已访问完」。
错误现象:仅用 bool visited[],会把反向边(back edge)误判为环;或者漏掉跨连通分量的环(其实不会,但状态不清会导致逻辑混乱)。
vector<int> state(n, 0):0 = 未访问,1 = 访问中(在当前 DFS 栈上),2 = 已完成state[u] = 1,返回前设 state[u] = 2v 且 state[v] == 1 → 立刻返回 true(发现环)indeg 数组越界、状态变量复用、节点编号与数组下标错位,都会让结果看起来“偶尔对偶尔错”。 上一篇:优秀记者的素质与能力要求
下一篇:非凡仙途赵云神将实战技巧解析
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
9