[數據結構]迪傑斯特拉(Dijkstra)算法

基本思想

     經過Dijkstra計算圖G中的最短路徑時,須要指定起點vs(即從頂點vs開始計算)。java

     此外,引進兩個集合S和U。S的做用是記錄已求出最短路徑的頂點,而U則是記錄還未求出最短路徑的頂點(以及該頂點到起點vs的距離)。數組

     初始時,S中只有起點vs;U中是除vs以外的頂點,而且U中頂點的路徑是"起點vs到該頂點的路徑"。而後,從U中找出路徑最短的頂點,並將其加入到S中;接着,更新U中的頂點和頂點對應的路徑。 而後,再從U中找出路徑最短的頂點,並將其加入到S中;接着,更新U中的頂點和頂點對應的路徑。 ... 重複該操做,直到遍歷完全部頂點。url

操做步驟

(1) 初始時,S只包含起點vs;U包含除vs外的其餘頂點,且U中頂點的距離爲"起點vs到該頂點的距離"[例如,U中頂點v的距離爲(vs,v)的長度,而後vs和v不相鄰,則v的距離爲∞]。spa

(2) 從U中選出"距離最短的頂點k",並將頂點k加入到S中;同時,從U中移除頂點k。.net

(3) 更新U中各個頂點到起點vs的距離。之因此更新U中頂點的距離,是因爲上一步中肯定了k是求出最短路徑的頂點,從而能夠利用k來更新其它頂點的距離;例如,(vs,v)的距離可能大於(vs,k)+(k,v)的距離。3d

(4) 重複步驟(2)和(3),直到遍歷完全部頂點。code

 

接下來作一個簡單例子求解:blog

 

 

package com.darrenchan.graph; import java.util.ArrayList; import java.util.List; public class ShortestPathDijkstra { /** 鄰接矩陣 */
    private int[][] matrix; /** 表示正無窮 */
    private int MAX_WEIGHT = Integer.MAX_VALUE; /** 頂點集合 */
    private String[] vertexes; /** * 建立圖 */
    private void createGraph(int index) { matrix = new int[index][index]; vertexes = new String[index]; int[] v0 = { 0, 1, 5, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT }; int[] v1 = { 1, 0, 3, 7, 5, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT }; int[] v2 = { 5, 3, 0, MAX_WEIGHT, 1, 7, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT }; int[] v3 = { MAX_WEIGHT, 7, MAX_WEIGHT, 0, 2, MAX_WEIGHT, 3, MAX_WEIGHT, MAX_WEIGHT }; int[] v4 = { MAX_WEIGHT, 5, 1, 2, 0, 3, 6, 9, MAX_WEIGHT }; int[] v5 = { MAX_WEIGHT, MAX_WEIGHT, 7, MAX_WEIGHT, 3, 0, MAX_WEIGHT, 5, MAX_WEIGHT }; int[] v6 = { MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, 3, 6, MAX_WEIGHT, 0, 2, 7 }; int[] v7 = { MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, 9, 5, 2, 0, 4 }; int[] v8 = { MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, 7, 4, 0 }; matrix[0] = v0; matrix[1] = v1; matrix[2] = v2; matrix[3] = v3; matrix[4] = v4; matrix[5] = v5; matrix[6] = v6; matrix[7] = v7; matrix[8] = v8; vertexes[0] = "v0"; vertexes[1] = "v1"; vertexes[2] = "v2"; vertexes[3] = "v3"; vertexes[4] = "v4"; vertexes[5] = "v5"; vertexes[6] = "v6"; vertexes[7] = "v7"; vertexes[8] = "v8"; } /** * Dijkstra最短路徑。 * * vs -- 起始頂點(start vertex) 即,統計圖中"頂點vs"到其它各個頂點的最短路徑。 */
    public void dijkstra(int vs) { // flag[i]=true表示"頂點vs"到"頂點i"的最短路徑已成功獲取
        boolean[] flag = new boolean[vertexes.length]; // U則是記錄還未求出最短路徑的頂點(以及該頂點到起點s的距離),與 flag配合使用,flag[i] == true 表示U中i頂點已被移除
        int[] U = new int[vertexes.length]; // 前驅頂點數組,即,prev[i]的值是"頂點vs"到"頂點i"的最短路徑所經歷的所有頂點中,位於"頂點i"以前的那個頂點。
        int[] prev = new int[vertexes.length]; // S的做用是記錄已求出最短路徑的頂點
        String[] S = new String[vertexes.length]; // 步驟一:初始時,S中只有起點vs;U中是除vs以外的頂點,而且U中頂點的路徑是"起點vs到該頂點的路徑"。
        for (int i = 0; i < vertexes.length; i++) { flag[i] = false; // 頂點i的最短路徑還沒獲取到。
            U[i] = matrix[vs][i]; // 頂點i與頂點vs的初始距離爲"頂點vs"到"頂點i"的權。也就是鄰接矩陣vs行的數據。
 prev[i] = 0; //頂點i的前驅頂點爲0
 } // 將vs從U中「移除」(U與flag配合使用)
        flag[vs] = true; U[vs] = 0; // 將vs頂點加入S
        S[0] = vertexes[vs]; // 步驟一結束 //步驟四:重複步驟二三,直到遍歷完全部頂點。 // 遍歷vertexes.length-1次;每次找出一個頂點的最短路徑。
        int k = 0; for (int i = 1; i < vertexes.length; i++) { // 步驟二:從U中找出路徑最短的頂點,並將其加入到S中(若是vs頂點到x頂點還有更短的路徑的話,那麼 // 必然會有一個y頂點到vs頂點的路徑比前者更短且沒有加入S中 // 因此,U中路徑最短頂點的路徑就是該頂點的最短路徑) // 即,在未獲取最短路徑的頂點中,找到離vs最近的頂點(k)。
            int min = MAX_WEIGHT; for (int j = 0; j < vertexes.length; j++) { if (flag[j] == false && U[j] < min) { min = U[j]; k = j; } } //將k放入S中
            S[i] = vertexes[k]; //步驟二結束 //步驟三:更新U中的頂點和頂點對應的路徑 //標記"頂點k"爲已經獲取到最短路徑(更新U中的頂點,即將k頂點對應的flag標記爲true)
            flag[k] = true; //修正當前最短路徑和前驅頂點(更新U中剩餘頂點對應的路徑) //即,當已經"頂點k的最短路徑"以後,更新"未獲取最短路徑的頂點的最短路徑和前驅頂點"。
            for (int j = 0; j < vertexes.length; j++) { //以k頂點所在位置連線其餘頂點,判斷其餘頂點通過最短路徑頂點k到達vs頂點是否小於目前的最短路徑,是,更新入U,不是,不作處理
                int tmp = (matrix[k][j] == MAX_WEIGHT ? MAX_WEIGHT : (min + matrix[k][j])); if (flag[j] == false && (tmp < U[j])) { U[j] = tmp; //更新 j頂點的最短路徑前驅頂點爲k
                    prev[j] = k; } } //步驟三結束
 } //步驟四結束 // 打印dijkstra最短路徑的結果
        System.out.println("起始頂點:" + vertexes[vs]); for (int i = 0; i < vertexes.length; i++) { System.out.print("最短路徑(" + vertexes[vs] + "," + vertexes[i] + "):" + U[i] + "  "); List<String> path = new ArrayList<>(); int j = i; while (true) { path.add(vertexes[j]); if (j == 0) break; j = prev[j]; } for (int x = path.size()-1; x >= 0; x--) { if (x == 0) { System.out.println(path.get(x)); } else { System.out.print(path.get(x) + "->"); } } } System.out.println("頂點放入S中的順序:"); for (int i = 0; i< vertexes.length; i++) { System.out.print(S[i]); if (i != vertexes.length-1) System.out.print("-->"); } } public static void main(String[] args) { ShortestPathDijkstra dij = new ShortestPathDijkstra(); dij.createGraph(9); dij.dijkstra(0); } }

 

參考:https://blog.csdn.net/CmdSmith/article/details/56839285v8

相關文章
相關標籤/搜索