java實現Dijkstra算法
Dijkstra
public class Dijkstra {
private static final int INF = Integer.MAX_VALUE;
/**
* 初始化距離矩陣
*
* @param graph 圖
* @return 距離矩陣
*/
private static int[][] initDistance(GraphMatrix graph) {
int vertexNum = graph.getVertexNum();
int[][] result = new int[vertexNum][vertexNum];
// 初始化距離矩陣
for (int i = 0; i < vertexNum; i++) {
for (int j = 0; j < vertexNum; j++) {
result[i][j] = graph.edges[i][j];
if (i != j && result[i][j] == 0) {
result[i][j] = INF;
}
}
}
return result;
}
private static void showInfo(int[] dist, int[] prev) {
System.out.print("距離向量 dist:");
for (int val : dist) {
if (val == INF) {
System.out.printf("%4s ", "INF");
} else {
System.out.printf("%4d ", val);
}
}
System.out.print("\n前驅結點 prev:");
for (int val : prev) {
System.out.printf("%4d ", val);
}
System.out.println();
}
private static void dijkstra(GraphMatrix<String> graph, String value) {
dijkstra(graph, graph.getVertexIndex(value));
}
//計算一個頂點到其它一個頂點的最短距離
public static void dijkstra(GraphMatrix graph, int v0) {
int vertexNum = graph.getVertexNum();
boolean[] visited = new boolean[vertexNum];
int[][] distance = initDistance(graph);
int[] dist = new int[vertexNum];
int[] prev = new int[vertexNum];
//初始化visited、dist和path
for (int i = 0; i < vertexNum; i++) {
//一開始假定取直達路徑最短
dist[i] = distance[v0][i];
visited[i] = false;
//直達情況下的最後經由點就是出發點
if (i != v0 && dist[i] < INF)
prev[i] = v0;
else
prev[i] = -1; //無直達路徑
}
//初始時源點v0∈visited集,表示v0 到v0的最短路徑已經找到
visited[v0] = true;
// 下來假設經由一個點中轉到達其餘各點,會近些,驗證之
// 再假設經由兩個點中轉,會更近些,驗證之,.....
// 直到窮舉完所有可能的中轉點
int minDist;
int v = 0;
//除了v0,剩下vertexNum - 1個結點
for (int i = 0; i < vertexNum - 1; i++) {
showInfo(dist, prev);
//挑一個距離最近經由點,下標裝入 v
minDist = INF;
for (int j = 0; j < vertexNum; j++) {
if (!visited[j] && dist[j] < minDist) {
v = j;// 經由頂點j中轉則距離更短
minDist = dist[j];
}
}
visited[v] = true;
/*頂點v併入S,由v0到達v頂點的最短路徑爲min.
假定由v0到v,再由v直達其餘各點,更新當前最後一個經由點及距離*/
for (int j = 0; j < vertexNum; j++) {
if (!visited[j] && distance[v][j] < INF) {
if (minDist + distance[v][j] < dist[j]) {
//如果多經由一個v點到達j點的 最短路徑反而要短,就更新
dist[j] = minDist + distance[v][j];
//經由點的序號
prev[j] = v;
}
}
}
}
printPath(graph, v0, dist, prev);
}
//v0爲出發節點
private static void printPath(GraphMatrix graph, int v0, int[] dist, int[] prev) {
//由於記錄的中途節點是倒序的,所以使用棧(先進後出),獲得正序
LinkedList<Integer> stack = new LinkedList<>();
//打印從出發節點到各節點的最短距離和經過的路徑
for (int i = 0; i < graph.getVertexNum(); i++) {
int j = i;
//如果j有中途節點
while (prev[j] != -1) {
stack.push(j); //將j壓入堆
j = prev[j]; //將j的前箇中途節點賦給j
}
stack.push(j);
System.out.print(graph.vertexList.get(v0) + "-->" +
graph.vertexList.get(i) + " 的最短路徑是:" + dist[i]);
System.out.print(", ");
//先進後出,獲得正序
while (!stack.isEmpty()) {
System.out.print(graph.vertexList.get(stack.pop()));//打印堆的頭節點
if (!stack.isEmpty()) {
System.out.print("->");
}
}
System.out.println();
}
}
public static void main(String[] args) {
GraphMatrix<String> graph = new GraphMatrix<>("ABCD");
graph.type = GraphMatrix.GraphType.DIRECTED_GRAPH;
graph.addEdge("A", "B", 1);
graph.addEdge("A", "C", 2);
graph.addEdge("A", "D", 3);
graph.addEdge("B", "A", 4);
graph.addEdge("C", "B", 5);
graph.addEdge("C", "D", 1);
graph.addEdge("D", "B", 1);
graph.addEdge("D", "C", 2);
graph.information();
dijkstra(graph, "B");
}
}
log
距離向量 dist: 4 0 INF INF
前驅結點 prev: 1 -1 -1 -1
距離向量 dist: 4 0 6 7
前驅結點 prev: 1 -1 0 0
距離向量 dist: 4 0 6 7
前驅結點 prev: 1 -1 0 0
B-->A 的最短路徑是:4, B->A
B-->B 的最短路徑是:0, B
B-->C 的最短路徑是:6, B->A->C
B-->D 的最短路徑是:7, B->A->D