《挑戰程序設計競賽》裏面介紹了三種方法: Bellman-Ford、Dijkstra and Floyd算法
三者區別也都很明顯:優化
Bellman-Ford:spa
求單源最短路,能夠判斷有無負權迴路(如有,則不存在最短路), 時效性較好,時間複雜度O(VE)。設計
Bellman-Ford算法是求解單源最短路徑問題的一種算法。隊列
單源點的最短路徑問題是指: 給定一個加權有向圖G和源點s,對於圖G中的任意一點v,求從s到v的最短路徑。it
與Dijkstra算法不一樣的是,在Bellman-Ford算法中,邊的權值能夠爲負數。 設想從咱們能夠從圖中找到一個環路(即從v出發,通過若干個點以後又回到v)且這個環路中全部邊的權值之和爲負。那麼經過這個環路,環路中任意兩點的最短路徑就能夠無窮小下去。若是不處理這個負環路,程序就會永遠運行下去。 而Bellman-Ford算法具備分辨這種負環路的能力。ast
Dijkstra:程序設計
求單源、無負權的最短路。時效性較好,時間複雜度爲O(V*V+E)。 源點可達的話,O(V*lgV+E*lgV)=>O(E*lgV)。 當是稀疏圖的狀況時,此時E=V*V/lgV,因此算法的時間複雜度可爲O(V^2) 。如果斐波那契堆做優先隊列的話,算法時間複雜度,則爲O(V*lgV + E)。 test
Floyd:效率
求多源、無負權邊的最短路。用矩陣記錄圖。時效性較差,時間複雜度O(V^3)。 Floyd-Warshall算法(Floyd-Warshall algorithm)是解決任意兩點間的最短路徑的一種算法,能夠正確處理有向圖或負權的最短路徑問題。
Floyd-Warshall算法的時間複雜度爲O(N^3),空間複雜度爲O(N^2)。
Floyd-Warshall的原理是動態規劃: 設Di,j,k爲從i到j的只以(1..k)集合中的節點爲中間節點的最短路徑的長度。 若最短路徑通過點k,則Di,j,k = Di,k,k-1 + Dk,j,k-1; 若最短路徑不通過點k,則Di,j,k = Di,j,k-1。 所以,Di,j,k = min(Di,k,k-1 + Dk,j,k-1 , Di,j,k-1)。
在實際算法中,爲了節約空間,能夠直接在原來空間上進行迭代,這樣空間可降至二維。 Floyd-Warshall算法的描述以下: for k ← 1 to n do for i ← 1 to n do for j ← 1 to n do if (Di,k + Dk,j < Di,j) then Di,j ← Di,k + Dk,j; 其中Di,j表示由點i到點j的代價,當Di,j爲 ∞ 表示兩點之間沒有任何鏈接。
後來,我看Bellman-Ford的隊列優化,SPFA(Shortest Path Faster Algorithm )。
SPFA:
是Bellman-Ford的隊列優化,時效性相對好,時間複雜度O(kE)。(k<<V)。
與Bellman-ford算法相似,SPFA算法採用一系列的鬆弛操做以獲得從某一個節點出發到達圖中其它全部節點的最短路徑。所不一樣的是,SPFA算法經過維護一個隊列,使得一個節點的當前最短路徑被更新以後沒有必要馬上去更新其餘的節點,從而大大減小了重複的操做次數。
SPFA算法能夠用於存在負數邊權的圖,這與dijkstra算法是不一樣的。
與Dijkstra算法與Bellman-ford算法都不一樣,SPFA的算法時間效率是不穩定的,即它對於不一樣的圖所須要的時間有很大的差異。
在最好情形下,每個節點都只入隊一次,則算法實際上變爲廣度優先遍歷,其時間複雜度僅爲O(E)。另外一方面,存在這樣的例子,使得每個節點都被入隊(V-1)次,此時算法退化爲Bellman-ford算法,其時間複雜度爲O(VE)。
SPFA算法在負邊權圖上能夠徹底取代Bellman-ford算法,另外在稀疏圖中也表現良好。可是在非負邊權圖中,爲了不最壞狀況的出現,一般使用效率更加穩定的Dijkstra算法,以及它的使用堆優化的版本。一般的SPFA算法在一類網格圖中的表現不盡如人意。