推出一個新系列,《看圖輕鬆理解數據結構和算法》,主要使用圖片來描述常見的數據結構和算法,輕鬆閱讀並理解掌握。本系列包括各類堆、各類隊列、各類列表、各類樹、各類圖、各類排序等等幾十篇的樣子。mysql
Floyd是一種經典的多源最短路徑算法,它經過動態規劃的思想來尋找給定加權圖中的多源點之間的最短路徑,算法時間複雜度是O(n3)。之因此叫Floyd是由於該算法發明人之一是Robert Floyd,他是1978年圖靈獎得到者,同時也是斯坦福大學計算機科學系教授。算法
對於n個點的加權圖,從加權圖的權值矩陣開始,遞歸地更新n次最終求得每兩點之間的最短路徑矩陣。即加權圖的鄰接矩陣爲,按必定公式對該矩陣進行遞歸更新,初始時矩陣爲D(0),第一次,根據公式用D(0)構建出矩陣D(1);第二次,根據公式用D(1)構建出矩陣D(2);以此類推,根據公式用D(n-1)構造出矩陣D(n),D(n)即爲圖的距離矩陣,i行j列表示頂點i到頂點j的最短距離。sql
如何理解這種動態規劃算法呢?能夠理解爲逐一選擇中轉點,而後針對該中轉點,全部以此爲中轉點的其它點都要根據規定進行更新,這個規定就是原來兩點之間的距離若是經過該中轉點變小了則更新距離矩陣。好比選擇「1」做爲中轉點,原來「02」之間的距離爲5,經過中轉點1後(即路徑變爲「012」)距離爲4,變小了,那麼就更新距離矩陣對應的元素,由5更新爲4。當圖中全部頂點都被做爲中轉點處理之後,那麼獲得的最後距離矩陣就是多源最短距離矩陣了。數組
設爲i到j的中間節點編號不超過k的最短距離,當k=0時,,對於n個頂點的圖,咱們要求的i到j的最短距離便是。bash
如今咱們創建和之間的遞歸關係,對於任意k,,因而能夠根據該遞歸關係獲得最終的最短路徑,即中間節點編號不超過n-1的最短距離。網絡
Floyd算法核心就是下列五行代碼,能夠體會一下,三個for循環嵌套,最外層的k便是循環取不一樣中轉點時的狀況,分別讓圖中每一個頂點做爲中轉點去更新距離,完成全部循環後就是最終的最短距離矩陣。數據結構
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(d[i][k]+d[k][j]<d[i][j])
d[i][j]=d[i][k]+d[k][j];
複製代碼
優勢:容易理解,能夠算出任意兩個節點之間的最短距離,代碼編寫簡單。對於稠密圖效果最佳,邊權可正可負。併發
缺點:時間複雜度比較高,不適合計算大量數據。機器學習
對於一個擁有7個頂點的無向加權圖,分別用0-6來表示圖的每一個頂點,每條邊上的數字爲對應的權重。數據結構和算法
首先根據每條邊的權重來初始化距離矩陣,這是一個[7x7]的矩陣,行列分別對應兩個頂點,好比第0行第1列表示頂點0到頂點1,對應的值爲3,即權值爲3。以此類推,其它元素分別表明對應邊的權重。
逐一查找看是否有以0爲中轉點使得距離更短,實際上並不用比較全部矩陣的元素,只需比較知足if (i != j && j != k && i != k)
條件的元素,即都爲0的對角線和中轉點對應的行列不用比較,由於對角線上的元素表示頂點本身到本身的距離,因此無需比較,而中轉點對應的行列表示頂點到中轉點的距離,也無需比較。
比較d[1][2]
與d[1][0]+d[0][2]
,由於1<3+5,因此不更新d[1][2]
。
往下,比較d[1][3]
與d[1][0]+d[0][3]
,由於4<3+INF,因此不更新d[1][3]
。
往下,比較d[1][4]
與d[1][0]+d[0][4]
,由於INF<3+INF,因此不更新d[1][4]
。接着往下d[1][5]
、d[1][6]
兩個元素狀況相似。
比較d[2][1]
與d[2][0]+d[0][1]
,由於1<3+5,因此不更新d[2][1]
。
往下,比較d[2][3]
與d[2][0]+d[0][3]
,由於4<5+INF,因此不更新d[2][3]
。
往下,比較d[2][4]
與d[2][0]+d[0][4]
,由於8<5+INF,因此不更新d[2][4]
。
往下,比較d[2][5]
與d[2][0]+d[0][5]
,由於2<5+INF,因此不更新d[2][5]
。
往下,比較d[2][6]
與d[2][0]+d[0][6]
,由於INF<5+INF,因此不更新d[2][6]
。
比較d[3][1]
與d[3][0]+d[0][1]
,由於4<INF+3,因此不更新d[3][1]
。
相似地,剩下的元素所有都不更新,最後比較完d[6][5]
與d[6][0]+d[0][5]
後即完成了以0做爲中轉點的所有比較工做。
逐一查找看是否有以1爲中轉點使得距離更短,比較d[0][2]
與d[0][1]+d[1][2]
,
由於5>3+1,因此將d[0][2]
的值更新爲4。
比較d[0][3]
與d[0][1]+d[1][3]
,
由於INF>3+4,因此將d[0][3]
的值更新爲7。
第0行接着的三個元素都不更新,到第2行後,比較d[2][0]
與d[2][1]+d[1][0]
,
由於5>1+3,因此將d[2][0]
的值更新爲4。第二行剩餘的元素都無需更新。
開始第3行,比較d[3][0]
與d[3][1]+d[1][0]
,
由於INF>4+3,因此將d[3][0]
的值更新爲7。
接着以頂點1做爲中轉點時剩餘的所有元素都無需更新。
逐一查找看是否有以2爲中轉點使得距離更短,比較d[0][1]
與d[0][2]+d[2][1]
,由於3<4+1,因此d[0][1]
不更新。
比較d[0][3]
與d[0][2]+d[2][3]
,由於7<4+4,因此d[0][3]
不更新。
比較d[0][4]
與d[0][2]+d[2][4]
,
由於INF>4+8,因此將d[0][4]
的值更新爲12。
相似地,對以頂點2做爲中轉點的所有剩餘元素進行比較更新。
逐一查找看是否有以3爲中轉點使得距離更短,比較d[0][1]
與d[0][3]+d[3][1]
,由於3<7+4,因此d[0][1]
不更新。
比較d[0][2]
與d[0][3]+d[3][2]
,由於4<7+4,因此d[0][2]
不更新。
相似地,對以頂點3做爲中轉點的所有剩餘元素進行比較更新。
逐一查找看是否有以4爲中轉點使得距離更短,比較d[0][1]
與d[0][4]+d[4][1]
,由於3<12+9,因此d[0][1]
不更新。
比較d[0][2]
與d[0][4]+d[4][2]
,由於4<12+8,因此d[0][2]
不更新。
相似地,對以頂點4做爲中轉點的所有剩餘元素進行比較更新。
逐一查找看是否有以5爲中轉點使得距離更短,比較d[0][1]
與d[0][5]+d[5][1]
,由於3<6+3,因此d[0][1]
不更新。
比較d[0][2]
與d[0][5]+d[5][2]
,由於4<6+2,因此d[0][2]
不更新。
相似地,對以頂點5做爲中轉點的所有剩餘元素進行比較更新。
逐一查找看是否有以6爲中轉點使得距離更短,比較d[0][1]
與d[0][6]+d[6][1]
,由於3<9+6,因此d[0][1]
不更新。
比較d[0][2]
與d[0][6]+d[56][2]
,由於4<9+5,因此d[0][2]
不更新。
相似地,對以頂點6做爲中轉點的所有剩餘元素進行比較更新。
將全部頂點做爲中轉點處理後,最終獲得了一個矩陣,這個矩陣就是圖的每一個頂點兩兩最短距離矩陣。好比a[0][4]=12
就是頂點0到頂點4的最短距離爲12。同時能夠看到距離矩陣是以對角線爲軸對稱的。
-------------推薦閱讀------------
個人開源項目彙總(機器&深度學習、NLP、網絡IO、AIML、mysql協議、chatbot)
跟我交流,向我提問:
歡迎關注: