1. 程式人生 > >資料結構篇:校園最短路徑導航(二:弗洛伊德演算法理解與應用)

資料結構篇:校園最短路徑導航(二:弗洛伊德演算法理解與應用)

求最短路徑最常用的有迪傑斯特拉(Dijkstra)和弗洛伊德(Floyd)演算法兩種。本著簡潔為王道的信條,我選擇了Floyd演算法。

Floyd演算法

首先來看一個簡單圖,紅色標記代表在陣列的下標,橙色標記代表距離(邊權值)

我們用D[6][6]這個矩陣儲存兩點之間最短路徑,用P[6][6]這個矩陣儲存路徑

兩個矩陣初始化如下,若兩點不直接聯通,則初始化為無窮大

D[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
P[6][6]
  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矩陣如下
D[6][6]
  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
P[6][6]
  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;
}