在數據結構的學習當中,圖的處理是必不可少的一項,對圖進行處理時,最短路徑的求取具有較強的使用性和可行性,在此,我簡單地對求取最短路徑的算法之一——弗洛伊德算法做出簡單的講解。
弗洛伊德算法在實現的時候一個重要的特點就是用循環(huán)的嵌套來進行逐個的判斷和更新。此算法區(qū)分于迪杰斯特拉算法的很大的優(yōu)點就是弗洛伊德算法可以在實現過后實現了圖中每一個結點的對其余各個結點的最短路徑,而后者只是針對一個目標結點計算出該結點到其他結點的最短路徑。但是,由于這次只是做弗洛伊德算法的講解,對于迪杰斯特拉算法便不予贅述。
如果要求任意兩個結點之間的最短路徑,我們可能已經有了簡單的想法,在兩個結點之間存在直接的路徑時,比較這個路徑和經過一次結點的中轉,甚至二次、三次、以及多次的中轉之后的權值之和比較,最短的權值之和就可以確定該路徑為最短路徑;若兩者沒有直接路徑,則需考慮在經過結點的中轉以后,無論經過了幾次中轉結點,只要選出權值最短的路徑,該路徑就是最短路徑。
這便是最短路徑的求取方法。
這個過程看似實現較難,但加上了一些輔助變量后,便可以順利實現。
但是要加入哪些輔助變量呢?首先需要考慮到的是path數組存放計算出的最短路徑的結果。行標表示起點結點,列標表示終點結點,則該位置存放的數據則是終點結點的前一個結點。
例如:從a到達c的最短路徑為:a—》b—》c;若a的下標是1;c的下標是4;b的下標是2;則path[1][4]=2;若從c到e的最短路徑是c—》d—》a—》e;c,d,a,e的下標分別為3,4,1,5;
則path[3][5]=1;在查找最短路徑時的順序則是path[3][5]=1,path[3][1]=4;path[3][4]=3;路徑順序就為:下標5《--1《--4《--3。
另外,需要加入輔助數組D,該數組用于記錄兩結點直接的最短路徑長度如D[0][3]=3;表示從0到3的最短路徑長度為3;
現在,讓我們回到上述自己設想的問題,如何比較兩個結點之間的路徑長度和呢?
在弗洛伊德算法中,采用的方法是權值的更新,以下是弗洛伊德的具體算法,以便于講解
下面開始對代碼展開講解:
個人認為,算法的實現可以分為兩部分,其中每一部分可以用以上的兩個for循環(huán)來劃分,第一個for循環(huán)如下,進行的是權值和路徑的初始化
D[i][j]=G.arc[i][j]; ? ? ? ? ?//將下標為i的結點與相關的結點權值初始化,如果有直接路徑,則長度是已知權值,否則的初始化結果是無窮
if (D[i][j]<Maxint)
p[i][j]=i; ? ? ? ? ? ? ? ? ? ? ? //已初始化后,有直接路徑的話終點結點的前一個結點便是起點結點
else
p[i][j]=0; ? ? ? ? ? ? ? ? ? ? ?//沒有直接路徑,進行特殊標記。
進行了初始化之后,數組D內的元素應該與圖D的權值數組G.arc相等,并且數組path內的數據也根據圖中結點間的關系獲得了初值。
第二部分體現為針對兩個目標結點加入圖中的每一個結點作為中轉結點進行路徑長度的判斷,根據判斷結果更新兩個數組內容,這個算法很容易使人聯想到密碼破解時使用的窮舉法。
代碼如下:
for (i=0;i<G.vexnum;i++)
for(j=0;j<G.vexnum;j++) ? ? ?//起始結點
for(k=0;k<G.vexnum;k++) ? ?//終點結點
if (D[j][k]>D[j][i]+D[i][k]) ? ? //j,k是需要更新的兩個結點,現在欲在這兩個結點中加入下標為i的結點,并判斷加入新的結點以后的路徑長度。
{
D[j][k]=D[j][i]+D[i][k];
p[j][k]=p[k][i]; ? ? ? ? ? ? ? ? ? //可以更新,則進行數據更新。
}
到此,循環(huán)結束,最短路徑的查找也完成。
需要說明的是,每一次數據的更新,path數組都保存有前一個結點的信息,如圖:
首先path[0][1]=0;D[0][1]=6;之后,有初始化后的結果:path[0][2]=0,D[0][2]=1,2和1之間沒有路徑故D[2][1]=Maxint,path[0][1],D[0][1]無需更新,之后,判斷0和3,D[0][3]=Maxint是初始化的結果,更新加入2之后成了path[0][3]=2;D[0][3]=3;path[2][3]=0,D[2][3]=2,path[3][1],D[3][1]=1加入任意結點之后無需更新,故保持;再進行path[0][1],D[0][1]的判斷時,嘗試加入結點2,不成功,再嘗試加入點3時,由于D[0][3]已經更新為3,所以滿足更新條件,D[0][1]=4,path[0][1]=3完成了從0到1中間大于1個中轉結點的實現。
總結在于,第二部分使用三個for語句的嵌套起到了重要的作用,數據的更新和信息的保存也需要準確理解。