大話數據結構學習筆記 - 圖的最短路徑之Dijkstra算法

大話數據結構學習筆記 - 圖的最短路徑之Dijkstra算法

最短路徑

最短路徑是圖中的重要問題,對於網圖非網圖來說,最短路徑的含義也是不同的。由於非網圖沒有邊上的權值,所謂的最短路徑,其實就是指兩頂點之間經過的邊數最少的路徑。而對於網圖來說,最短路徑,是指兩頂點之間經過的邊上的權值之和最少的路徑,並且我們稱路徑上的第一個頂點是源點,最後一個頂點是終點。當然非網圖可以理解爲所有邊的權值都爲1的網

迪傑斯塔拉(Dijkstra)算法

迪傑斯特拉(Dijkstra)算法是典型的最短路徑算法,用於計算一個結點到其他結點的最短路徑。算法的主要特點是以起始點爲中心向外層層擴展(廣度優先搜索思想), 直到擴展到終點爲止

基本思想

通過Dijkstra計算圖G中的最短路徑時,需要指定起點v0, 即從v0點開始計算。 起初,設置S數組表示已求得最短路徑的頂點, U數組表示起點到各頂點的最短距離, 即起點到各頂點最短路徑的權值和。P數組表示最短路徑中的各頂點

算法圖解

Graph_Shortest_Path_Dijkstra_image_1

以上圖左圖爲例進行算法演示,右圖爲構建的無向圖鄰接矩陣。final數組爲已求得最短路徑的頂點集合,D數組爲起點到各頂點的最短路徑的權值和, P數組爲最短路徑的路徑的頂點。

初始狀態final數組表示起點v0到某頂點是否已求得最短路徑的標記, 即若v0vw已有結果,則final[w]=1。起初final數組均爲0D數組爲{65535, 1, 5, 65535, 65535, 65535, 65535, 65535, 65535}

第一步 :將起始點v0加入到final數組, final[0] = 1, 此時final數組爲{1, 0, 0, 0, 0, 0, 0, 0, 0}, 且v0v0路徑爲0. D數組爲{0, 1, 5, 65535, 65535, 65535, 65535, 65535, 65535}

第二步: 尋找與final數組中已有頂點的最短距離, 並更新D數組。 與v0相連的頂點最短距離爲v1頂點,權值爲1, 故將v1加入到final數組。 final = {1,1,0,0,0,0,0,0,0,0}

第三步: 對更新後的final數組進行路徑權值和的更新, 即D的更新 , 在原來的權值和基礎上,更新新加入的頂點與其他各頂點得到權值和,比如final數組新增加v1頂點, 對D數組進行更新後, D = {0, 1, 4, 8, 6, 65535, 65535, 65535, 65535}

第四步: 尋找與final集合權值最短的頂點, 頂點v0、v1不參與, 故爲頂點v2, 距離爲4, 然後更新final數組和D數組 final = {1,1,1,0,0,0,0,0,0}D = {0,1,4,8,5,11,65535, 65535, 65535}, 此時P數組爲P = {0,0,1,1,2,2,0,0,0}

循環依次繼續, 最後final數組包含所有頂點, D數組包含起點到其餘所有頂點的最短距離, P數組包含起點到任意頂點的路徑長度。即迪傑斯塔拉算法解決了從某個源點到其餘各頂點的最短路徑問題

代碼

無向圖結構

#define MAXVEX 10
#define INF 65535
typdef int Patharc[MAXVEX];  // 用於存儲最短路徑下標的數組
typedef int ShortPathTable[MAXVEX];  // 用於存儲起點到各點最短路徑的權值和

typedef struct
{
    int vexs[MAXVEX];
    int arc[MAXVEX][MAXVEX];
    int numVertexes, numEdges;
}MGraph;

Dijkstra算法

/* Dijkstra算法, 求有向網 G 的 v0 頂點到其餘頂點 v 最短路徑 P[v] 及帶權長度 D[v], P[v] 的值爲前驅頂點下標,
 * D[v] 表示 v0 到 v 的最短路徑長度和 */
void ShortestPath_Dijkstra(MGraph G, int v0, ShortPathTable *D, Patharc *P)
{
    int min, k, final[MAXVEX];  /* final[w] = 1 表示求得頂點 v0 至 vw 的最短路徑 */
    for(int v = 0; v < G.numVertexes; v++)  /* 初始化數據 */
    {
        final[v] = 0;     /* 全部頂點初始化爲未知最短路徑狀態 */
        (*D)[v] = G.arc[v0][v];   /* 將與 v0 頂點有連線的頂點加上權值 */
        (*P)[v] = -1;     /* 初始化路徑數組 P 爲 0 */
    }
    final[v0] = 1;   /* v0 至 v0 不需要求路徑 */
    (*D)[v0] = 0;    /* v0 至 v0 路徑爲 0 */

    /* 開始主循環, 每次求得 v0 到某個 v 頂點的最短路徑 */
    for(int v = 1; v < G.numVertexes; v++)
    {
        min = INF;   /* 當前所知離 v0 頂點的最近距離 */
        for(int w = 0; w < G.numVertexes; w++)   /* 尋找離 v0 最近的頂點 */
        {
            if(!final[w] && (*D)[w] < min)
            {
                min = (*D)[w];    /* w 頂點離 v0 頂點更近 */
                k = w;
            }
        }
        final[k] = 1;   /* 將目前找到的最近的頂點置爲 1 */
        for(int w = 0; w < G.numVertexes; w++)   /* 更新當前最短路徑及距離 */
        {
            /* 如果經過 v 頂點的路徑比現在這條路徑的長度短的話 */
            if(!final[w] && (min + G.arc[k][w]) < (*D)[w])
            {
                /* 說明找到了更短的路徑, 修改 D[w] 和 P[w] */
                (*D)[w] = min + G.arc[k][w];   /* 修改當前路徑長度 */
                (*P)[w] = k;
            }
        }
    }
}

算法源碼

鄰接矩陣最短路徑之Dijkstra算法

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章