图算法可视化

图算法回答不同问题:哪个依赖可以先执行?一个起点到各顶点的最小成本是多少?连接整张图的总成本如何最小?拓扑排序回答顺序问题,Dijkstra 和 Bellman-Ford 求单源最短路,最小生成树优化整体连接成本。

最短路径树保证从源点出发的路线最短,不保证选中边的总和最小。最小生成树最小化总边权,却可能让某对顶点之间的路线更长。

目标比较

算法目标下一步选择主要条件典型时间
拓扑排序按依赖排列顶点Kahn 选零入度点,DFS 在返回时记录完成点有向无环图O(V + E)
Dijkstra单源最短距离暂定距离最小的未确定顶点边权非负O((V + E) log V)
Bellman-Ford单源最短距离每轮松弛每条边源点可达范围没有负环O(V · E)
Prim最小生成树当前树与外部之间的最轻边无向连通图O((V + E) log V)
Kruskal最小生成树连接不同分量的下一条最轻边无向连通图O(E log E)

Dijkstra 与 Prim 都可以使用最小堆,但优先值不同:前者是从源点出发的整条路径成本,后者是一条跨割边的权重。Kruskal 不围绕源点生长,而是排序所有边,用并查集根判断是否可以连接。

建议学习顺序

学过 DFS 和 BFS 后,先看拓扑排序。Kahn 从零入度点开始移除依赖,DFS 在回退时记录完成顺序。同一 DAG 可以产生两个不同的合法顺序;环形预设让两种算法都拒绝把部分结果当成完整答案。

再看 Dijkstra,跟踪暂定距离与松弛。尚未确定的路线可能被后续路径改善。负权预设展示条件边界:边能降低成本时,最小距离出堆后直接定案就不再安全。

随后在 Bellman-Ford 中选择 Dijkstra 陷阱预设,即刚才算错的同一张图。它不使用优先队列或永久锁定,而是重复松弛边,最多经过 V−1 轮得到最短路,再用额外检查判断是否存在可达负环。

进入最小生成树的 Prim 模式。左侧记录显示当前割,每次接受最轻跨割边。负权在这里不会造成 Dijkstra 的问题。

保持图不变,切换到 Kruskal。下方是全局排序的边,左侧是连通分量。若两端根相同,已接受的路径会指出候选边将闭合哪个环。

观察重点

  • 分清堆里的优先值是整条路径成本,还是单条边权。
  • 拓扑排序中,Kahn 用正入度说明仍有前置约束;DFS 需要先处理尚未完成的后继,再记录当前顶点。
  • 最便宜的候选也必须满足算法不变量,才能安全接受。
  • 观察拒绝步骤:Dijkstra 丢弃过期堆条目,生成树算法拒绝会闭环的边。
  • 尝试不连通图。得到的部分森林不能当成整图的生成树。

全部图算法可视化课程

改变图或算法,逐步对照 Python 或 JavaScript 代码查看轨迹。