1. 程式人生 > >[數據結構]迪傑斯特拉(Dijkstra)算法

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

graph tegra src img exe 經歷 mage length arraylist

基本思想

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

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

初始時,S中只有起點vs;U中是除vs之外的頂點,並且U中頂點的路徑是"起點vs到該頂點的路徑"。然後,從U中找出路徑最短的頂點,並將其加入到S中;接著,更新U中的頂點和頂點對應的路徑。 然後,再從U中找出路徑最短的頂點,並將其加入到S中;接著,更新U中的頂點和頂點對應的路徑。 ... 重復該操作,直到遍歷完所有頂點。

操作步驟

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

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

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

(4) 重復步驟(2)和(3),直到遍歷完所有頂點。

技術分享圖片

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

技術分享圖片

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/56839285

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