Dijkstra算法是一种用于在带非负权重的图中找到单源最短路径的经典算法。以下是该算法的关键点总结:
算法步骤
- 初始化:
-
将起始节点的距离设为0,其他所有节点的距离设为无穷大(∞)。
-
使用优先队列(通常为最小堆)存储节点及其当前最短距离,起始节点首先入队。
-
维护一个集合记录已处理的节点。
- 处理节点:
-
从优先队列中取出距离最小的节点
u
。 -
若
u
已处理过,则跳过;否则标记为已处理。 -
遍历
u
的所有邻居v
:-
计算从起始节点经
u
到v
的路径长度:alt = dist[u] + weight(u, v)
。 -
若
alt < dist[v]
,则更新v
的距离,并将v
重新加入优先队列。
-
- 终止条件:
- 当优先队列为空时,算法结束。此时
dist[]
中存储了所有节点的最短距离。
关键特性
-
贪心策略:每次选择当前最短路径的节点,确保非负权重下局部最优即全局最优。
-
时间复杂度:
-
使用二叉堆:
O((V + E) log V)
,适用于稀疏图。 -
使用斐波那契堆:
O(E + V log V)
,理论最优但实现复杂。 -
邻接矩阵遍历:
O(V²)
,适合稠密图。
-
-
适用条件:边权重必须非负,否则可能无法得到正确结果。
示例与验证
图结构:
-
节点:A, B, C, D
-
边:A→B(3), A→C(5), B→C(1), B→D(2), C→D(3)
执行过程:
-
初始队列:
[(0, A)]
,距离:A=0
,其他∞。 -
处理A,更新B(3)、C(5),队列变为
[(3, B), (5, C)]
。 -
处理B,更新C(4)、D(5),队列变为
[(4, C), (5, D)]
。 -
处理C,尝试更新D(7 > 5,不更新),队列剩余
[(5, D)]
。 -
处理D,结束。
结果:最短距离为A→B(3)
, A→B→C(4)
, A→B→D(5)
。
代码实现(Python示例)
import heapq
def dijkstra(graph, start):
distances = {node: float('infinity') for node in graph}
distances[start] = 0
heap = [(0, start)]
processed = set()
while heap:
current_dist, u = heapq.heappop(heap)
if u in processed:
continue
processed.add(u)
for v, weight in graph[u].items():
distance = current_dist + weight
if distance < distances[v]:
distances[v] = distance
heapq.heappush(heap, (distance, v))
return distances
# 示例图
graph = {
'A': {'B': 3, 'C': 5},
'B': {'C': 1, 'D': 2},
'C': {'D': 3},
'D': {}
}
print(dijkstra(graph, 'A')) # 输出:{'A':0, 'B':3, 'C':4, 'D':5}
注意事项
-
负权边:Dijkstra算法无法处理,需改用Bellman-Ford算法。
-
路径回溯:可通过记录前驱节点(
prev[]
数组)重建最短路径。 -
重复入队:允许队列中存在同一节点的多个实例,但已处理节点会被跳过。
通过以上步骤和示例,Dijkstra算法能够高效求解非负权重图的单源最短路径问题。