過程
首先需要記錄每個點到原點的距離,這個距離會在每一輪遍歷的過程中刷新。每一個節點到原點的最短路徑是其上一個節點(前驅節點)到原點的最短路徑加上前驅節點到該節點的距離。以這個原則,經過N輪計算就能得到每一個節點的最短距離。
第一輪,可以計算出,2、3、4、5、6到原點1的距離分別為:[7, 9, -1, -1, 14]。-1表示無窮大。取其中最小的,為7,即可以確定1的最短路徑為0,2為下一輪的前驅節點。同時確定2節點的最短路徑為7,路線:1->2。
第二輪,取2節點為前驅節點,按照前驅節點的最短距離加上該節點與前驅節點的距離計算新的最短距離,可以得到3,4,5,6節點到原點的距離為:[17, 22, -1, -1],此時需要將這一輪得到的結果與上一輪的比較,3節點:17 > 9,最短路徑仍然為9;4節點:22 < 無窮大,刷新4節點的最短路徑為22;5節點:不變,仍然為無窮大;6節點:14 < 無窮大,取14,不變。則可以得到本輪的最短距離為:[9, 22, -1, 14],取最短路徑最小的節點,為3,作為下一輪的前驅節點。同時確定3節點的最短路徑為9,路線:1->3。
第三輪,同上,以3為前驅節點,得到4,5,6的計算距離為:[20, -1, 11],按照取最短路徑的原則,與上一輪的進行比較,刷新為:[20, –1, 11],選定6為下一輪的前驅節點。同時取定6的最短路徑為11,路線:1->3->6。
第四輪,同上,以6為前驅節點,得到4和5的計算距離為[20, 20],與上一輪進行比較,刷新后為[20, 20],二者相等只剩下兩個節點,並且二者想等,剩下的計算已經不需要了。則兩個節點的最短路徑都為20。整個計算結束。4的最短路徑為20,路線:1->3->4。5的最短路徑為20,路線:1->3->6->5。
如果二者不相等,則還需要進行第五輪,先確定二者中的一個的最短路徑和路線,再取定剩下的。直到整個5次循環都完成。
偽代碼
function Dijkstra(G, w, s) for each vertex v in V[G] //初始化 d[v] := infinity //將各點的已知最短距離先設成無窮大 previous[v] := undefined // 各點的已知最短路徑上的前趨都未知 d[s] := 0 // 因為出發點到出發點間不需移動任何距離,所以可以直接將s到s的最小距離設為0 S := empty set Q := set of all vertices while Q is not an empty set // Dijkstra算法主體 u := Extract_Min(Q) S.append(u) for each edge outgoing from u as (u,v) if d[v] > d[u] + w(u,v) // 拓展邊(u,v)。w(u,v)為從u到v的路徑長度。 d[v] := d[u] + w(u,v) // 更新路徑長度到更小的那個和值。 previous[v] := u // 記錄前面頂點
Code
public class Dijkstra { public static final int M = -1; public static void main(String[] args) { int[][] map1 = { { 0, 7, 9, M, M, 14 }, { 7, 0, 10, 15, M, M }, { 9, 10, 0, 11, M, 2 }, { M, 15, 11, 0, 6, M }, { M, M, M, 6, 0, 9 }, { 14, M, 2, M, 9, 0 } }; int orig = 0; int[] shortPath = Dijsktra(map1, orig); if (shortPath == null) { return; } for (int i = 0; i < shortPath.length; i++) { System.out.println("從" + (orig + 1) + "出發到" + (i + 1) + "的最短距離為:" + shortPath[i]); } } public static int[] Dijsktra(int[][] weight, int orig) { int n = weight.length; // 頂點個數 int[] shortest = new int[n]; // 存放從start到其他各點的最短路徑 boolean[] visited = new boolean[n]; // 標記當前該頂點的最短路徑是否已經求出,true表示已求出 // 初始化,第一個頂點求出 shortest[orig] = 0; visited[orig] = true; for (int count = 0; count != n - 1; count++) // 要加入n-1個頂點 { // 選出一個距離初始頂點最近的未標記頂點 int k = M; int dmin = M; for (int i = 0; i < n; i++) { if (!visited[i] && weight[orig][i] != M) { if (dmin == -1 || dmin > weight[orig][i]) { dmin = weight[orig][i]; k = i; } } } // 正確的圖生成的矩陣不可能出現K == M的情況 if (k == M) { System.out.println("the input map matrix is wrong!"); return null; } shortest[k] = dmin; visited[k] = true; // 以k為中間點,修正從原點到未訪問各點的距離 for (int i = 0; i < n; i++) { if (!visited[i] && weight[k][i] != M) { int callen = dmin + weight[k][i]; if (weight[orig][i] == M || weight[orig][i] > callen) { weight[orig][i] = callen; } } } } return shortest; } }
我是天王蓋地虎的分割線
參考:http://codeway.co/dijkstra%E7%AE%97%E6%B3%95%E6%B1%82%E8%A7%A3%E6%9C%80%E7%9F%AD%E8%B7%AF%E5%BE%84%E5%88%86%E6%9E%90/