尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Tarjan 强连通分量的栈:一张依赖图如何拆出环

Tarjan 强连通分量的栈:一张依赖图如何拆出环 模块依赖一旦出现环拓扑排序就会失败。本文用 Python 实现 Tarjan 强连通分量解释 index、lowlink 和栈成员的含义提供递归深度与自环测试。 同时说明边界、复杂度与可复现实验方便读者直接改造成自己的工具。 同时说明边界、复杂度与可复现实验方便读者直接改造成自己的工具。依赖图中 A 依赖 B、B 依赖 C、C 又依赖 A 时三个模块应该一起升级或一起隔离。只标记访问过的节点无法区分“已经结束的分支”和“当前路径上的回边”Tarjan 用栈成员状态补上这条信息。面试官先问环究竟是什么index 是节点第一次被发现的时间lowlink 是从当前 DFS 子树出发沿树边和回边能回到的最小 index。节点 u 满足 low[u]index[u] 时它就是一个强连通分量的根栈顶到 u 的节点可以一起出栈。lowlink 在记录哪条回边DFS 访问邻居 v若 v 未访问递归后 low[u]min(low[u],low[v])若 v 仍在栈中low[u]min(low[u],index[v])。发现根后不断 pop直到 u。已经出栈的节点不参与 lowlink 更新。走过 A-B-C-A图 A-B、B-C、C-A、C-D 中A 的 lowlink 最终为 0D 自己形成单点分量当 C 看到 A 仍在栈中时回边把 low[C] 拉回 index[A]环就被识别。为什么出栈不能提前lowlink 只沿当前 DFS 树和栈内回边传播。根节点没有更早的栈内祖先因此 lowindex若不满足说明仍有路径回到更早节点。每个节点入栈出栈一次复杂度线性。大图上的实现选择依赖扫描可能达到百万节点Python 递归要提高栈限制或改写为显式帧栈。输出分量后可缩点成 DAG。完整可运行代码importsysdefscc(graph):nlen(graph);sys.setrecursionlimit(max(1000,2*n10));idx0;st[];on[False]*n;ind[-1]*n;low[0]*n;out[]defdfs(u):nonlocalidx ind[u]low[u]idx;idx1;st.append(u);on[u]Trueforvingraph[u]:ifind[v]0:dfs(v);low[u]min(low[u],low[v])elifon[v]:low[u]min(low[u],ind[v])iflow[u]ind[u]:comp[]whileTrue:vst.pop();on[v]False;comp.append(v)ifvu:breakout.append(sorted(comp))foruinrange(n):ifind[u]0:dfs(u)returnsorted(out)if__name____main__:assertscc([[1],[2],[0,3],[]])[[0,1,2],[3]]assertscc([[0],[]])[[0],[1]]print(tarjan tests passed)逐行读代码闭包中的 idx 负责分配发现序号on明确节点是否仍在当前栈。递归调用返回后先更新 low再判断根。排序只用于让测试输出稳定不属于算法本身。工程扩展强连通分量缩点后得到 DAG可继续做关键路径、依赖层级或循环报告。若图来自外部文件应在读入时检查顶点编号和重复边。可复现实验运行脚本输出tarjan tests passed。测试覆盖三节点环、自环、孤立点和多条重复边可随机图与 Floyd 可达性定义的互相可达集合对照。复杂度分析时间 O(VE)空间 O(V)包括栈、编号数组和输出。递归版本受调用栈限制显式栈版本复杂度相同但代码更长。边界条件空图、孤立点、自环、平行边和超深链都要覆盖无向图不能直接套用有向图的 lowlink 规则。常见错误把所有访问过邻居都当回边、忘记判断 on-stack、出栈后仍更新 low以及根节点只弹一个元素都会切碎或合并错误的分量。可复制的测试用例执行两个断言再随机生成 n8 的有向图。用可达矩阵判断 i、j 是否互相可达将等价类与 Tarjan 输出比较。上线前检查栈状态只对仍在栈中的邻居更新根low 等于 index 才出栈缩点分量之间形成 DAG深度大图考虑显式栈总结Tarjan 的洞察是“正在处理”本身就是图的信息。栈把路径上下文保存下来lowlink 则把回到祖先的证据压缩成一个数字识别环因此不需要反复做全图搜索。标签Tarjan强连通分量图算法Python参考来源CSDN 数据结构与算法频道动态规划题型分类与解题套路复盘补充Tarjan 的洞察是“正在处理”本身就是图的信息。栈把路径上下文保存下来lowlink 则把回到祖先的证据压缩成一个数字识别环因此不需要反复做全图搜索。 依赖扫描可能达到百万节点Python 递归要提高栈限制或改写为显式帧栈。输出分量后可缩点成 DAG。复盘补充Tarjan 的洞察是“正在处理”本身就是图的信息。栈把路径上下文保存下来lowlink 则把回到祖先的证据压缩成一个数字识别环因此不需要反复做全图搜索。 依赖扫描可能达到百万节点Python 递归要提高栈限制或改写为显式帧栈。输出分量后可缩点成 DAG。复盘补充Tarjan 的洞察是“正在处理”本身就是图的信息。栈把路径上下文保存下来lowlink 则把回到祖先的证据压缩成一个数字识别环因此不需要反复做全图搜索。 依赖扫描可能达到百万节点Python 递归要提高栈限制或改写为显式帧栈。输出分量后可缩点成 DAG。复盘补充Tarjan 的洞察是“正在处理”本身就是图的信息。栈把路径上下文保存下来lowlink 则把回到祖先的证据压缩成一个数字识别环因此不需要反复做全图搜索。 依赖扫描可能达到百万节点Python 递归要提高栈限制或改写为显式帧栈。输出分量后可缩点成 DAG。复盘补充Tarjan 的洞察是“正在处理”本身就是图的信息。栈把路径上下文保存下来lowlink 则把回到祖先的证据压缩成一个数字识别环因此不需要反复做全图搜索。 依赖扫描可能达到百万节点Python 递归要提高栈限制或改写为显式帧栈。输出分量后可缩点成 DAG。复盘补充Tarjan 的洞察是“正在处理”本身就是图的信息。栈把路径上下文保存下来lowlink 则把回到祖先的证据压缩成一个数字识别环因此不需要反复做全图搜索。 依赖扫描可能达到百万节点Python 递归要提高栈限制或改写为显式帧栈。输出分量后可缩点成 DAG。复盘补充Tarjan 的洞察是“正在处理”本身就是图的信息。栈把路径上下文保存下来lowlink 则把回到祖先的证据压缩成一个数字识别环因此不需要反复做全图搜索。 依赖扫描可能达到百万节点Python 递归要提高栈限制或改写为显式帧栈。输出分量后可缩点成 DAG。复盘补充Tarjan 的洞察是“正在处理”本身就是图的信息。栈把路径上下文保存下来lowlink 则把回到祖先的证据压缩成一个数字识别环因此不需要反复做全图搜索。 依赖扫描可能达到百万节点Python 递归要提高栈限制或改写为显式帧栈。输出分量后可缩点成 DAG。复盘补充Tarjan 的洞察是“正在处理”本身就是图的信息。栈把路径上下文保存下来lowlink 则把回到祖先的证据压缩成一个数字识别环因此不需要反复做全图搜索。 依赖扫描可能达到百万节点Python 递归要提高栈限制或改写为显式帧栈。输出分量后可缩点成 DAG。复盘补充Tarjan 的洞察是“正在处理”本身就是图的信息。栈把路径上下文保存下来lowlink 则把回到祖先的证据压缩成一个数字识别环因此不需要反复做全图搜索。 依赖扫描可能达到百万节点Python 递归要提高栈限制或改写为显式帧栈。输出分量后可缩点成 DAG。复盘补充Tarjan 的洞察是“正在处理”本身就是图的信息。栈把路径上下文保存下来lowlink 则把回到祖先的证据压缩成一个数字识别环因此不需要反复做全图搜索。 依赖扫描可能达到百万节点Python 递归要提高栈限制或改写为显式帧栈。输出分量后可缩点成 DAG。复盘补充Tarjan 的洞察是“正在处理”本身就是图的信息。栈把路径上下文保存下来lowlink 则把回到祖先的证据压缩成一个数字识别环因此不需要反复做全图搜索。 依赖扫描可能达到百万节点Python 递归要提高栈限制或改写为显式帧栈。输出分量后可缩点成 DAG。复盘补充Tarjan 的洞察是“正在处理”本身就是图的信息。栈把路径上下文保存下来lowlink 则把回到祖先的证据压缩成一个数字识别环因此不需要反复做全图搜索。 依赖扫描可能达到百万节点Python 递归要提高栈限制或改写为显式帧栈。输出分量后可缩点成 DAG。
返回列表