資料結構篇:校園最短路徑導航(二:弗洛伊德演算法理解與應用)
阿新 • • 發佈:2018-12-21
求最短路徑最常用的有迪傑斯特拉(Dijkstra)和弗洛伊德(Floyd)演算法兩種。本著簡潔為王道的信條,我選擇了Floyd演算法。
Floyd演算法
首先來看一個簡單圖,紅色標記代表在陣列的下標,橙色標記代表距離(邊權值)
我們用D[6][6]這個矩陣儲存兩點之間最短路徑,用P[6][6]這個矩陣儲存路徑
兩個矩陣初始化如下,若兩點不直接聯通,則初始化為無窮大
A | B | C | D | E | F | |
A | 0 | 7 | ∞ | ∞ | 10 | 5 |
B | 7 | 0 | 8 | ∞ | ∞ | ∞ |
C | ∞ | 8 | 0 | 6 | ∞ | 5 |
D | ∞ | ∞ | 6 | 0 | 7 | ∞ |
E | 10 | ∞ | ∞ | 7 | 0 | 4 |
F | 5 | ∞ | 5 | ∞ | 4 | 0 |
A | B | C | D | E | F | |
A | 0 | 1 | 2 | 3 | 4 | 5 |
B | 0 | 1 | 2 | 3 | 4 | 5 |
C | 0 | 1 | 2 | 3 | 4 | 5 |
D | 0 | 1 | 2 | 3 | 4 | 5 |
E | 0 | 1 | 2 | 3 | 4 | 5 |
F | 0 | 1 | 2 | 3 | 4 | 5 |
核心程式碼
for (int k = 0; k < G->numVertexes; ++k)
{
for (int v = 0; v < G->numVertexes; ++v)
{
for (int w = 0; w < G->numVertexes; ++w)
{
if (D[v][w] > D[v][k] + D[k][w])
{
D[v][w] = D[v][k] + D[k][w];
P[v][w] = P[v][k];
}
}
}
}
其中k為中轉頂點下標,級無論走哪條路徑,都要經過k下標的頂點,v代表起始頂點,w代表終點。
當取k=0時代表所有路徑都經過下標為0的地點(A)
- v取2,w取3,即從C到D,有C-A-D,可惜這個路徑的和不小於C-D的路徑大小,所以D陣列不會有變化。
- v取1,w取4,即從B到E,有B-A-E,發現它的值為17,小於B-E的無窮大,所以D[1][4]由無窮大改為17,因為D陣列變化了,所以P陣列也要跟著變化,把P[1][4]改為當前P[1][0],代表從B到E下一節點為A
- 同理在k取0時,將這個時間複雜度為O(6^2)的迴圈走完,那麼D和P矩陣如下
A | B | C | D | E | F | |
A | 0 | 7 | ∞ | ∞ | 10 | 5 |
B | 7 | 0 | 8 | ∞ | 17 | 12 |
C | ∞ | 8 | 0 | 6 | ∞ | 5 |
D | ∞ | ∞ | 6 | 0 | 7 | ∞ |
E | 10 | 17 | ∞ | 7 | 0 | 4 |
F | 5 | 12 | 5 | ∞ | 4 | 0 |
A | B | C | D | E | F | |
A | 0 | 1 | 2 | 3 | 4 | 5 |
B | 0 | 1 | 2 | 3 | 0 | 0 |
C | 0 | 1 | 2 | 3 | 4 | 5 |
D | 0 | 1 | 2 | 3 | 4 | 5 |
E | 0 | 0 | 2 | 3 | 4 | 5 |
F | 0 | 0 | 2 | 3 | 4 | 5 |
然後取k=1,2,3,4,5遍歷完成後,D和P就是我們的目標陣列了。
輸出結果
這個就比較簡單了,比如我輸入1,4,代表我想知道從B走到E的最短路徑,先輸出最短路徑為D[1][4]。然後就是具體的路徑,我們找到P[1][4],發現它等於0,意味著從B走到E要先走B-A,然後我們看P[0][4],發現它等於4,也就是E,到達終點。
void AdjacencyList::ShowShortestResult(int originPos,int endPos) {
int temp;
cout << "地點" << _mapName[originPos] << "到地點" << _mapName[endPos] << "最短距離為" << ShortestPathvalue[originPos][endPos] << endl;
temp = ShortestPathmatrix[originPos][endPos];
cout<<"具體路徑為:"<<_mapName[originPos]<<"——>";
while (temp!=endPos){
cout<<_mapName[temp]<<"——>";
temp = ShortestPathmatrix[temp][endPos];
}
cout<<_mapName[endPos]<<endl;
}