给定带权有向图G =(V,E),其中每条边的权是非负实数。另外,还给定V中的一个顶点,称为源。现在要计算从源到所有其它各顶点的最短路长度。这里路的长度是指路上各边权之和。这个问题通常称为单源最短路径问题。
Dijkstra算法是解单源最短路径问题的贪心算法。其基本思想是,设置顶点集合S并不断地作贪心选择来扩充这个集合。一个顶点属于集合S当且仅当从源到该顶点的最短路径长度已知。
初始时,S中仅含有源。设u是G的某一个顶点,把从源到u且中间只经过S中顶点的路称为从源到u的特殊路径,并用数组dist记录当前每个顶点所对应的最短特殊路径长度。Dijkstra算法每次从V-S中取出具有最短特殊路长度的顶点u,将u添加到S中,同时对数组dist作必要的修改。一旦S包含了所有V中顶点,dist就记录了从源到所有其它顶点之间的最短路径长度。
例如,对下图中的有向图,应用Dijkstra算法计算从源顶点1到其它顶点间最短路径的过程列在下表中。
Dijkstra算法的迭代过程:
具体代码实现:
1: import java.util.Stack;
2:
3: public class Dijkstra {
4: static int MAX_SIZE = 6;
5: public static void dijkstra(int startVertex, float[][] weight,
6: float[] minDist, int[] prev, int[][] path) {
7: int n = minDist.length - 1;
8: if (startVertex < 1 || startVertex > n)
9: return;
10: boolean[] s = new boolean[n + 1]; //是否将蓝点集加入红点集的标志
11:
12: // startVertex为顶点1
13: minDist[startVertex] = 0; //初始红点集
14: s[startVertex] = true;
15: for (int i = 2; i <= n; i++) {
16: minDist[i] = weight[startVertex][i]; //设置初始距离为weight<s,i>
17: s[i] = false;
18: if (minDist[i] == Float.MAX_VALUE) {
19: prev[i] = 0;
20: path[i][startVertex] = 0;
21: } else {
22: prev[i] = startVertex;
23: path[i][startVertex] = 1;
24: }
25: }
26: // 扩充红点集
27: for (int i = 1; i < n; i++) {
28: float temp = Float.MAX_VALUE;
29: int u = startVertex;
30: // 在当前蓝点集中选估计距离最小的顶点j
31: for (int j = 2; j <= n; j++) {
32: if ((!s[j]) && (minDist[j] < temp)) {
33: u = j;//k是V集合中具有最短“特殊路径的顶点”,所谓特殊路径即是从顶点v到k只经过U中的顶点
34: temp = minDist[j];
35: }
36: }
37:
38: // 如果仍为无穷大,则说明为不连通图
39: if (Float.MAX_VALUE == temp)
40: return;
41:
42: s[u] = true; // 将蓝点集u扩充到红点集
43: // 调整源点s与剩余蓝点之间的距离
44: for (int j = 2; j <= n; j++)
45: if ((!s[j]) && (weight[u][j] < Float.MAX_VALUE)) {
46: float newDist = minDist[u] + weight[u][j];
47: if (newDist < minDist[j]) {
48: minDist[j] = newDist;
49: prev[j] = u;
50:
51: path[j][startVertex] = u;
52: }
53: }
54: }
55: }
56:
57: public static void main(String args[]) {
58: float weight[][] = new float[MAX_SIZE][MAX_SIZE];//边权
59: float[] minDist = new float[MAX_SIZE]; //源点到其它顶点的最短距离数组
60: int[] prev = new int[MAX_SIZE]; // s到t经过顶点的集合
61: int[][] path = new int[MAX_SIZE][MAX_SIZE];
62: for (int i = 0; i < MAX_SIZE; i++)
63: for (int j = 0; j < MAX_SIZE; j++)
64: weight[i][j] = Float.MAX_VALUE;
65: for (int i = 0; i < MAX_SIZE; i++)
66: for (int j = 0; j < MAX_SIZE; j++)
67: path[i][j] = 0;
68: weight[1][2] = 10;
69: weight[1][4] = 30;
70: weight[1][5] = 100;
71: weight[2][3] = 50;
72: weight[3][5] = 10;
73: weight[4][3] = 20;
74: weight[4][5] = 60;
75: int startVertex = 1;// 假设从顶点1处出发
76:
77: dijkstra(startVertex, weight, minDist, prev, path);
78: System.out.println("从1出发到2、3、4、5的最短路径依次是:");
79: for (int j = 2; j < MAX_SIZE; j++) {
80: System.out.println(minDist[j]);
81: }
82: System.out.println("path矩阵如下:");
83: for (int i = 0; i < MAX_SIZE; i++) {
84: for (int j = 0; j < MAX_SIZE; j++) {
85: System.out.print(path[i][j] + " ");
86: }
87: System.out.println();
88: }
89: System.out.println("从1到5最短路径经过的点为:");
90: int endVertex = 5;
91: Stack<Integer> stack = new Stack<Integer>();
92: System.out.print(startVertex+" ");
93: printPath(path, startVertex, endVertex,stack);
94:
95: }
96:
97: // 栈处理
98: static void printPath(int[][] path, int startVertex, int endVertex,Stack<Integer> pathStack) {
99: if (path[endVertex][startVertex] != 0)//&&path[endVertex][startVertex]!=startVertex
100: {
101: pathStack.push(endVertex);
102: int temp = path[endVertex][startVertex];
103: printPath(path, startVertex, temp,pathStack);
104: System.out.print(pathStack.pop() + " ");
105: }
106: }
107: }