Dijkstra算法

在所有边权非负的图中,贪心地选择当前距离源点最近的未确定顶点,通过松弛操作更新邻接顶点

定义

形式化定义

输入: 带权有向图 ,所有边权 ,源点 输出: 对每个从 可达的顶点 ,前驱子图 是最短路径树

关键变量:

  • :从源点 到顶点 的当前最短路径估计值(上界)
  • :顶点 在最短路径树中的前驱
  • :已确定最短路径的顶点集合
  • :优先队列(最小堆),存储未确定顶点,以 值为key

算法步骤:

  1. 初始化 ,其余 ,所有顶点加入
  2. 非空时:取出 最小的顶点 ,加入 ,对 的每条出边执行 RELAX

核心性质

性质描述
前提条件所有边权
数组实现,适合稠密图
二叉堆实现,适合稀疏图
斐波那契堆实现
负权边不适用,可能产生错误结果
BFS特例当所有边权为1时退化为BFS

关系网络

graph LR
    A["Dijkstra算法"] --> B["松弛操作"]
    A --> C["优先队列"]
    A --> D["最短路径树"]
    A --> E["单源最短路径"]
    A --> F["Prim算法"]
    A --> G["Bellman-Ford算法"]
    A --> H["A*算法"]
    H -.->|"Dijkstra + 启发函数"| A

章节扩展

第22章:单源最短路径

Dijkstra算法是CLRS第22.3节介绍的高效单源最短路径算法,由Edsger W. Dijkstra于1956年提出。

算法伪代码:

DIJKSTRA(G, w, s)
1  INITIALIZE-SINGLE-SOURCE(G, s)
2  S ← ∅
3  Q ← G.V
4  while Q ≠ ∅
5      u ← EXTRACT-MIN(Q)
6      S ← S ∪ {u}
7      for each vertex v ∈ G.Adj[u]
8          RELAX(u, v, w)

正确性(定理22.6):

  • 循环不变式:每次 EXTRACT-MIN 之前,对所有
  • 初始化:,空集上全称命题平凡成立
  • 维护:反证法——设取出 ,考虑最短路径上第一个不在 中的顶点 ,则 (由归纳),且 (边权非负 + EXTRACT-MIN),矛盾
  • 终止:,所有

不适用于负权边的原因: 证明依赖 (从 的路径边权非负)。若存在负权边,此不等式不成立,已加入 的顶点可能需要被重新更新,但算法不会回头。

补充

补充说明

  • Dijkstra于1956年在阿姆斯特丹咖啡馆构思了该算法,1959年发表在《Numerische Mathematik》上
  • GPS导航系统的核心路径规划引擎基于Dijkstra算法或其变种(A*、双向Dijkstra、收缩层次等)
  • OSPF路由协议使用Dijkstra算法计算最短路径树
  • A算法 = Dijkstra + 启发函数 ,当 时A退化为Dijkstra

参见