概述
感觉迪杰斯特拉好难,才学会的这个算法,所以写下博客加深理解。
Dijkstra算法是从一个顶点到其余各顶点的最短路径算法,解决的是带权图中最短路径问题。
Dijkstra算法主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。
Dijkstra算法将图中的节点集分为:
1.最短路径计算完成的节点集S
2.最短路径未计算完成的节点集T
首先选择一个起点,然后每次将从T中挑选“起点->某节点”的路径最短的节点加入S,并更新”起点“经由”某节点”到T中剩余节点的更短距离,直到T中的节点全部加入S中,它在每次都选择一个距离起点最近的节点加入最短路径节点集合。
算法流程
下面我们使用这个图走一遍算法流程,这里我们选择节点A作为起点,计算从起点A到剩余节点的最短路径。
我们使用shortest[ ]、visited[ ]这两个数组,
shortest[index]:存储A到该节点的最短路径,
visited[index]存储v0到该节点的最短路径是否求出。
S为已求出最短路径的节点集,T为未求出最短路径的节点集。起点只允许将S中的节点作为中间节点来计算到达其它节点的最短路径,不允许将T中的节点作为中间节点来计算到达其它节点的最短路径。随着S中节点的增加,起点可达的节点才会增加。
初始状态下,起点只可达B,C,G节点。
1.
将起点A加入S中,对shortest[ ]、visited[ ]进行更新。
2.
S中现有节点A,起点可达T中的B,C,G节点
节点A->节点B距离为5,节点A->节点C距离为7,节点A->节点G距离为2
按距离从小到大排序,因此选择将节点G加入S中。
更新“起点将节点G作为中间节点到达其它节点的距离”。
3.
S中现有节点A和节点G,起点可达T中的节点C,B,E,F
A->C=7,A->B=5,A->G->E=6,A->G->F=8
因此选择将节点B加入S中
更新“起点将节点B作为中间节点到达其它节点的距离”
4.
S中现有节点A,B,G,起点可达T中的节点C、D、E,F
A->C=7,A->G->E=6,A->G->F=8,A->B->D=14
因此选择将节点E加入S中
更新“起点将节点E作为中间节点到达其它节点的距离”
5.
S中现有节点A、B、E、G,起点可达T中的节点C、D、F,
A->C=7,A->G->F=8,A->B->D=14
因此选择将节点C加入S中
更新“起点将节点C作为中间节点到达其它节点的距离”
6.
S中现有节点A、B、C、E、G,起点可达T中的节点D、F
A->F=8,A->B->D=14
因此选择将节点F加入S中
更新“源点将节点F作为中间节点到达其它节点的距离。”
7.
S中现有节点A、B、C、E、F,G
起点可达T中的节点D
A->G->F->D=12
因此选择将节点D加入S中
更新“源点将节点D作为中间节点到达其它节点的距离。”
结束:到此起点到所有节点的最短路径都求出来了。
JAVA代码实现
package 尚硅谷_数据结构和算法.十种算法.迪杰斯特拉算法;
public class DijstraAlgorithm {
//不能设置为Integer.MAX_VALUE,否则两个Integer.MAX_VALUE相加会溢出导致出现负权
public static int M = 100000;
//定义七个顶点
private static char[] vertex = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};
public static void main(String[] args) {
//初始化邻接矩阵
int[][] matrix = new int[vertex.length][vertex.length];
matrix[0] = new int[]{M, 5, 7, M, M, M, 2};
matrix[1] = new int[]{5, M, M, 9, M, M, 3};
matrix[2] = new int[]{7, M, M, M, 8, M, M};
matrix[3] = new int[]{M, 9, M, M, M, 4, M};
matrix[4] = new int[]{M, M, 8, M, M, 5, 4};
matrix[5] = new int[]{M, M, M, 4, 5, M, 6};
matrix[6] = new int[]{2, 3, M, M, 4, 6, M};
//调用dijstra算法计算最短路径
dijstra(matrix, 0);
}
/**
* @param matrix:邻接矩阵
* @param source:起点
*/
public static void dijstra(int[][] matrix, int source) {
//最短路径长度
int[] shortest = new int[matrix.length];
//判断该点的最短路径是否求出
int[] visited = new int[matrix.length];
//存储输出路径
String[] path = new String[matrix.length];
//初始化输出路径
for (int i = 0; i < matrix.length; i++) {
path[i] = vertex[source] + "->" + vertex[i];
}
//初始化起点,将起点放入S
shortest[source] = 0;
visited[source] = 1;
for (int i = 1; i < matrix.length; i++) { //i从1开始,因为起点已经加入S了
int min = M;
int index = -1;
//找出某节点到起点路径最短
for (int j = 0; j < matrix.length; j++) {
//已经求出最短路径的节点不需要再加入计算并判断加入节点后是否存在更短路径
if (visited[j] == 0 && matrix[source][j] < min) {
min = matrix[source][j];
index = j;
}
}
//更新最短路径,标记起点到该节点的最短路径已经求出
shortest[index] = min;
visited[index] = 1;
//更新从index跳到其它节点的较短路径
for (int m = 0; m < matrix.length; m++) {
if (visited[m] == 0 && matrix[source][index] + matrix[index][m] < matrix[source][m]) {
matrix[source][m] = matrix[source][index] + matrix[index][m];
path[m] = path[index] + "->" + vertex[m];
}
}
}
//打印最短路径
for (int i = 0; i < matrix.length; i++) {
if (i != source) {
if (shortest[i] == M) {
System.out.println(vertex[source] + "到" + vertex[i] + "不可达");
} else {
System.out.println(vertex[source] + "到" + vertex[i] + "的最短路径为:" + path[i] + ",最短距离是:" + shortest[i]);
}
}
}
}
}
输出:
A到B的最短路径为:A->B,最短距离是:5
A到C的最短路径为:A->C,最短距离是:7
A到D的最短路径为:A->G->F->D,最短距离是:12
A到E的最短路径为:A->G->E,最短距离是:6
A到F的最短路径为:A->G->F,最短距离是:8
A到G的最短路径为:A->G,最短距离是:2