數據結構之Dijkstra's Algorithm


 

概述

Dijkstra算法是由荷蘭計算機科學家狄克斯特拉(Dijkstra)於1959 年提出的,因此又叫狄克斯特拉算法。是從一個頂點到其余各頂點的最短路徑算法,解決的是有向圖中最短路徑問題。

其基本原理是:每次新擴展一個距離最短的點,更新與其相鄰的點的距離。當所有邊權都為正時,由於不會存在一個距離更短的沒擴展過的點,所以這個點的距離永遠不會再被改變,因而保證了算法的正確性。不過根據這個原理,用Dijkstra求最短路的圖不能有負權邊,因為擴展到負權邊的時候會產生更短的距離,有可能就破壞了已經更新的點距離不會改變的性質。

舉例來說,如果圖中的頂點表示城市,而邊上的權重表示著城市間開車行經的距離。 Dijkstra算法可以用來找到兩個城市之間的最短路徑。

Dijkstra算法的輸入包含了一個有權重的有向圖G,以及G中的一個來源頂點S。 我們以V表示G中所有頂點的集合。 每一個圖中的邊,都是兩個頂點所形成的有序元素對。(u,v)表示從頂點u到v有路徑相連。 我們以E所有邊的集合,而邊的權重則由權重函數w: E → [0, ∞]定義。 因此,w(u,v)就是從頂點u到頂點v的非負花費值(cost)。 邊的花費可以想像成兩個頂點之間的距離。任兩點間路徑的花費值,就是該路徑上所有邊的花費值總和。 已知有V中有頂點s及t,Dijkstra算法可以找到s到t的最低花費路徑(i.e. 最短路徑)。 這個算法也可以在一個圖中,找到從一個頂點s到任何其他頂點的最短路徑。

算法描述

這個算法是通過為每個頂點v保留目前為止所找到的從s到v的最短路徑來工作的。初始時,源點s的路徑長度值被賦為0(d[s]=0), 同時把所有其他頂點的路徑長度設為無窮大,即表示我們不知道任何通向這些頂點的路徑(對於V中所有頂點v除s外d[v]= ∞)。當算法結束時,d[v]中儲存的便是從s到v的最短路徑,或者如果路徑不存在的話是無窮大。 Dijstra算法的基礎操作是邊的拓展:如果存在一條從u到v的邊,那么從s到u的最短路徑可以通過將邊(u,v)添加到尾部來拓展一條從s到v的路徑。這條路徑的長度是d[u]+w(u,v)。如果這個值比目前已知的d[v]的值要小,我們可以用新值來替代當前d[v]中的值。拓展邊的操作一直執行到所有的d[v]都代表從s到v最短路徑的花費。這個算法經過組織因而當d[u]達到它最終的值的時候沒條邊(u,v)都只被拓展一次。

算法維護兩個頂點集S和Q。集合S保留了我們已知的所有d[v]的值已經是最短路徑的值頂點,而集合Q則保留其他所有頂點。集合S初始狀態為空,而后每一步都有一個頂點從Q移動到S。這個被選擇的頂點是Q中擁有最小的d[u]值的頂點。當一個頂點u從Q中轉移到了S中,算法對每條外接邊(u,v)進行拓展。

 

時間復雜度

我們可以用大O符號將Dijkstra算法的運行時間表示為邊數m和頂點數n的函數。

Dijkstra算法最簡單的實現方法是用一個鏈表或者數組來存儲所有頂點的集合Q,所以搜索Q中最小元素的運算(Extract-Min(Q))只需要線性搜索Q中的所有元素。這樣的話算法的運行時間是O(n2)。

對於邊數少於n2稀疏圖來說,我們可以用鄰接表來更有效的實現Dijkstra算法。同時需要將一個二叉堆或者斐波納契堆用作優先隊列來尋找最小的頂點(Extract-Min)。當用到二叉堆的時候,算法所需的時間為O((m+n)log n),斐波納契堆能稍微提高一些性能,讓算法運行時間達到O(m + n log n)。 相關問題和算法

在Dijkstra算法的基礎上作一些改動,可以擴展其功能。例如,有時希望在求得最短路徑的基礎上再列出一些次短的路徑。為此,可先在原圖上計算出最短路徑,然后從圖中刪去該路徑中的某一條邊,在余下的子圖中重新計算最短路徑。對於原最短路徑中的每一條邊,均可求得一條刪去該邊后子圖的最短路徑,這些路徑經排序后即為原圖的一系列次短路徑。

OSPF(open shortest path first, 開放最短路徑優先)算法是Dijkstra算法在網絡路由中的一個具體實現。

與Dijkstra算法不同,Bellman-Ford算法可用於具有負花費邊的圖,只要圖中不存在總花費為負值且從源點 s 可達的環路(如果有這樣的環路,則最短路徑不存在,因為沿環路循環多次即可無限制的降低總花費)。

與最短路徑問題有關的一個問題是旅行商問題(traveling salesman problem),它要求找出通過所有頂點恰好一次且最終回到源點的最短路徑。該問題是NP難的;換言之,與最短路徑問題不同,旅行商問題不太可能具有多項式時間算法。

如果有已知信息可用來估計某一點到目標點的距離,則可改用A*算法,以減小最短路徑的搜索范圍。


 

From StanfordZhang

1. Dijkstra's Algorithm是解決單源最短路徑問題,即:從某個源點到其余各頂點的最短路徑;

2. Dijkstra's Algorithm中有兩上關鍵點要注意(這是我學習的時候不仔細,導致走了很多彎路)。這里先明確兩個集合:所有頂點集V和已選中頂點集S。

    (1)找到當前未選中點(V - S)中距離源點最近的點;

    (2)更新未選中點到源點的距離。

 


 

From 佐_翼

Dijkstra's 算法與最小生成樹的區別在於:

① 最小生成樹是對全圖而言的,而Dijkstra's算法是對某個結點而言的。

② 最小生成樹是連接所有結點的最短路徑,但是如果從某個結點出發,沿着最小生成樹到另一個結點的路徑不一定是最短的。      而在Dijkstra's樹中,從根結點到各葉子結點的路徑都是最短的。

③ 若Dijkstra's算法依次應用於每個頂點,最后可以得到任意兩個頂點之間的最短路徑,這就是通常所說的任意頂點對之間的最短路徑問題(all-pairs shortest paths,APAP)


 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM