交互式图论学习
交互式图论学习
Guest User
Using app without sign in
交互式最短路径计算器
在加权图中找到从源点到所有顶点的最短路径
选择算法并生成步骤以开始可视化
Dijkstra 算法在边权非负的加权图中计算从源节点到所有其他节点的最短路径。它由 Edsger Dijkstra 于 1959 年发表,至今仍是单源最短路径的标准算法,也是大多数实用路由系统的基础。
算法为每个节点维护一个临时距离,初始时除源点为零外均为无穷大。借助优先队列,它反复取出临时距离最小的未确定节点,将其标记为最终,并松弛每条出边:若经过当前节点的路径比邻居已记录的距离更短,就更新之。用二叉堆时运行时间为 O((V + E) log V)。非负权重至关重要;一条负边可能使已确定的节点失效。
Dijkstra 算法驱动 GPS 导航、OSPF 等互联网路由协议、航班与公交规划器以及网络延迟分析。在没有启发式时,它也用于游戏中的寻路。在面试中,它是加权最短路径问题的标准答案,也是讨论 A* 与 Bellman-Ford 权衡的起点。
Dijkstra 是一个贪心算法,其正确性只依赖一条论断:当前距离最近的未确定结点此后不可能再被改进。优先队列以 O(log V) 提供这个结点。
Dijkstra(图, 源点):
对每个结点 v: dist[v] = 无穷大
dist[源点] = 0
pq = 含 (0, 源点) 的优先队列
当 pq 非空时:
(d, u) = pq.取出最小()
若 d > dist[u]: 跳过 // 过期条目
对每条边 (u, v, w):
若 dist[u] + w < dist[v]:
dist[v] = dist[u] + w
父结点[v] = u
pq.插入((dist[v], v))过期条目检查很关键。多数标准库不支持在堆中直接减小键值,因此惯常做法是插入一个重复条目,并忽略任何记录距离已经对不上的条目。这称为惰性删除,也正是队列中条目数可能达到 E 而非 V 的原因。
从 A 出发在一个贪心选择确实奏效的加权图上运行 Dijkstra,观察已确定结点集合如何增长。
示例图: 无向边 A-B (4)、A-C (2)、C-B (1)、B-D (5) 和 C-D (8)。
最终距离为 A 0、C 2、B 3、D 8,到 D 的最短路径依次经过 A、C、B、D。注意权重为 4 的直接边 A-B 从未被使用:经由 C 只需 3。另外注意结点是按距离 0、2、3、8 的顺序被确定的,这正是贪心论证所依赖的性质。
时间: O((V + E) log V) · 空间: O(V)
使用二叉堆时,V 个结点各被取出一次,每次 O(log V);E 条边各可能触发一次插入,每次 O(log V),合计 O((V + E) log V)。采用惰性删除时堆中最多有 E 个条目,取出为 O(log E),但由于 E 至多为 V 的平方,log E 至多是 2 log V,界限不变。斐波那契堆把理论界限改进到 O(E + V log V),因为减小键值变为均摊 O(1),但其常数因子之大使得二叉堆在实践中通常更快。在稠密图上,直接扫描数组求最小值给出 O(V 的平方),当 E 接近 V 的平方时反而胜过堆。
Dijkstra 是加权最短路径的默认选择。用什么取代它,取决于你的图违反了它的哪条假设。
| 替代算法 | 以下情况更合适 | 代价 |
|---|---|---|
| BFS | 所有边权重相同,跳数即距离。严格更快。 | O(V + E) |
| Bellman-Ford | 存在负权边,贪心确定的论证因此失效。 | O(VE) |
| A* 搜索 | 你只要某个特定终点,并且有可采纳的启发函数,例如地图上的直线距离。 | 最坏 O((V + E) log V) |
| Floyd-Warshall | 你需要所有点对之间的距离,且图较小或较稠密。 | O(V^3) |
| 双向 Dijkstra | 单源、单目标、大图,并且边可以反向遍历。 | 探索结点数约减半 |
阅读完整文章: Shortest Path Algorithms Explained
相关算法: 贝尔曼-福特算法, 弗洛伊德-沃歇尔算法, 广度优先搜索