Dijkstra算法是一种经典的单源最短路径算法,适用于加权图,即图中边的权重可以是任意非负数。该算法由荷兰计算机科学家Edsger W. Dijkstra在1956年提出,并于1959年正式发表。它的基本思想是通过贪心策略,不断扩展最短路径的集合,直到找到从源点到所有其他顶点的最短路径。
算法步骤
- 初始化:
- 将所有顶点的最短路径估计值设置为正无穷大,除了源点,源点的最短路径估计值设置为0。
- 将所有顶点标记为未访问。
- 创建一个空的已访问顶点集合。
- 选择当前未访问顶点中最短路径估计值最小的顶点:
- 从所有未访问顶点中选择一个最短路径估计值最小的顶点,记为u。
- 更新邻接顶点的最短路径估计值:
- 对于顶点u的每一个邻接顶点v,如果通过u到达v的路径比当前已知的到v的最短路径更短,则更新v的最短路径估计值。
- 标记顶点u为已访问:
- 将顶点u标记为已访问,并将其加入已访问顶点集合。
- 重复步骤2到步骤4:
- 直到所有顶点都被访问过,或从源点到所有未访问顶点的最短路径都已经确定。
伪代码
以下是Dijkstra算法的代码:
import heapq
def dijkstra(graph, start):
# 初始化距离表,所有距离为无穷大
distances = {vertex: float('infinity') for vertex in graph}
# 起点的距离为0
distances[start] = 0
# 优先队列,存储(距离,顶点)
priority_queue = [(0, start)]
while priority_queue:
# 获取距离最小的顶点
current_distance, current_vertex = heapq.heappop(priority_queue)
# 如果从优先队列中取出的距离大于当前距离,则跳过(这是因为我们已经找到更短的路径)
if current_distance > distances[current_vertex]:
continue
# 更新相邻顶点的距离
for neighbor, weight in graph[current_vertex].items():
distance = current_distance + weight
# 如果找到更短的路径,更新距离表并加入优先队列
if distance < distances[neighbor]:
distances[neighbor] = distance
heapq.heappush(priority_queue, (distance, neighbor))
return distances
# 示例图,使用邻接表表示
graph = {
'A': {'B': 1, 'C': 4},
'B': {'A': 1, 'C': 2, 'D': 5},
'C': {'A': 4, 'B': 2, 'D': 1},
'D': {'B': 5, 'C': 1}
}
# 计算从顶点A到其他顶点的最短路径
start_vertex = 'A'
distances = dijkstra(graph, start_vertex)
print(f"从顶点 {start_vertex} 出发的最短路径距离:")
for vertex, distance in distances.items():
print(f"到顶点 {vertex} 的距离为 {distance}")
复杂度
- 时间复杂度:对于一个有n个顶点和m条边的图,使用二叉堆优化的Dijkstra算法的时间复杂度是O((n + m) log n)。
- 空间复杂度:主要用于存储图的结构、距离数组和优先队列,因此空间复杂度是O(n + m)。
示例
假设我们有一个图如下:
A
/ \\
1 4
/ \\
B---2---C
\\ /
5 1
\\ /
D
权重为边的长度。我们从A开始运行Dijkstra算法:
-
初始化:
dist[A] = 0 dist[B] = ∞ dist[C] = ∞ dist[D] = ∞
-
从A开始,更新B和C的距离:
dist[B] = 1 (A -> B) dist[C] = 4 (A -> C)
-
选择B,更新D的距离:
dist[D] = 6 (B -> D)
-
选择C,更新D的距离:
dist[D] = 5 (C -> D)
-
选择D,算法结束。
最终的最短路径距离:
dist[A] = 0
dist[B] = 1
dist[C] = 4
dist[D] = 5
Dijkstra算法通过逐步扩展已确定最短路径的顶点集合,保证每次选取的顶点都是当前未访问顶点中距离源点最近的,从而有效地找到从源点到所有其他顶点的最短路径。