在許多路由問題中,尋找圖中一個頂點到另一個頂點的最短路徑或最小帶權路徑是非常重要的提煉過程。正式表述為,給定一個帶權有向圖G = (V, E)
, 頂點s
到v
中頂點t
的最短路徑為在邊集E
中連線s
到t
代價最小的路徑。要做到這一點首先要解決更為一般的單源最短路徑問題。在單源最短路徑問題中,計算從一個起始頂點s
到其他與之相鄰頂點之間的最短路勁。
Dijkstra演算法
解決單源最短路徑問題的方法之一就是Dijkstra
演算法。Dijkstra
演算法會生成一顆最短路徑樹,樹的根為起始頂點s
, 樹的分支為從頂點s
到圖G
中所有其他頂點的最短路徑。此演算法要求圖中的所有權值均為非負數。與Prim
演算法類似,Dijkstra
演算法也採用貪心演算法,它總是將當前看起來最近的最短的邊加入最短路徑中。
從根本上來說,Dijkstra
演算法通過選擇一個頂點,並不斷探測與之相關的邊,類似廣度優先搜尋,找出當前距離最近的點。
演算法流程:
- 求從頂點
a
開始的單源最短路徑,就是圖中每個點距離a
的最短路。
- 選定
a
,標記訪問過了,首先初始化圖中各點與a
的距離,在實際程式碼中一般用一個陣列dist[i]
存放這個值,如果暫時不可達,存一個極大值在裡面。如圖,只有b
,c
直接與a
連線,這時候dist[b]=8
,dist[c]=4
。其它點的dist[i]=NaN,
後面的運算就是不斷更新這個dist
陣列。
- 再選出
dist
最小的元素擴充套件,很明顯是c
,標記visit
,這時候通過c
點,f
,e
也產生一個新的與a
的距離,這時候更新dist
陣列,他們之前與a的距離都是NaN
,當然只要原來與a
的距離大於通過c
與a
的距離,都需要更新。
- 再找出非
visit
中dist
最小的點,找到f
,因為b, d, e
都與f
相鄰,這時候比較通過f
後與a
的距離,如果比原來dist
短,就更新dist
。
- 選擇頂點
b
。
- 在選擇頂點
d, e
後形成最短路徑。
Dijkstra
演算法實現:
1 function Dijkstra(Graph, source):
2
3 create vertex set Q
4
5 for each vertex v in Graph: // Initialization
6 dist[v] ← INFINITY // Unknown distance from source to v
7 prev[v] ← UNDEFINED // Previous node in optimal path from source
8 add v to Q // All nodes initially in Q (unvisited nodes)
9
10 dist[source] ← 0 // Distance from source to source
11
12 while Q is not empty:
13 u ← vertex in Q with min dist[u] // Source node will be selected first
14 remove u from Q
15
16 for each neighbor v of u: // where v is still in Q.
17 alt ← dist[u] + length(u, v)
18 if alt < dist[v]: // A shorter path to v has been found
19 dist[v] ← alt
20 prev[v] ← u
21
22 return dist[], prev[]
複製程式碼