算法–基础–11–迪杰斯特拉(Dijkstra)
1、定义
- 最短路径算法,用于计算一个节点到其他节点的最短路径。
- 特点:是以起始点为中心向外层层扩展(广度优先搜索思想),直到扩展到终点为止。
2、算法思路
- 初始时,S只包含起点s;U包含除s外的其他顶点,且U中顶点的距离为"起点s到该顶点的距离"[例如,U中顶点v的距离为(s,v)的长度,然后s和v不相邻,则v的距离为∞]。
- 从U中选出"距离最短的顶点k",并将顶点k加入到S中;同时,从U中移除顶点k。
- 更新U中各个顶点到起点s的距离。之所以更新U中顶点的距离,是由于上一步中确定了k是求出最短路径的顶点,从而可以利用k来更新其它顶点的距离;例如,(s,v)的距离可能大于(s,k)+(k,v)的距离。
- 重复步骤2和3,直到遍历完所有顶点。
3、算法图解
选定A节点并初始化
执行上述2,3步骤,找出U集合中路径最短的节点D 加入S集合,从U中移除节点D,更新U中各个顶点到起点A的距离,根据(AD距离 + D到B,C,E的距离< A到B,C,E 的距离)来更新U集合
这时候 B, C 都为3,没关系。其实这时候他俩都是最短距离,如果从算法逻辑来讲的话,会先取到B点。 执行步骤2,3
思路就是这样,往后就是大同小异
4、代码实现
package Test;
import java.util.ArrayList;
import java.util.List;
public class Dijkstra {
public static final int M = 10000; // 代表正无穷
public static void main(String[] args) {
// 二维数组每一行分别是 A、B、C、D、E 各点到其余点的距离,
// A -> A 距离为0, 常量M 为正无穷
int[][] weight1 = {{0,4,M,2,M}, //A节点到A、B、C、D、E 各点到其余点的距离
{4,0,4,1,M}, //B节点到A、B、C、D、E 各点到其余点的距离
{M,4,0,1,3}, //C节点到A、B、C、D、E 各点到其余点的距离
{2,1,1,0,7}, //D节点到A、B、C、D、E 各点到其余点的距离
{M,M,3,7,0} //E节点到A、B、C、D、E 各点到其余点的距离
};
//测试A节点到其他节点的距离
int start = 0;
dijkstra(weight1, start);
}
/**
*
* 描述:将数字转换为对应的节点(A,B,C,D,E)
* @param
* @return
*/
public static String getNode(int i) {
String node=null;
switch (i) {
case 0:
node="A";
break;
case 1:
node="B";
break;
case 2:
node="C";
break;
case 3:
node="D";
break;
case 4:
node="E";
break;
default:
break;
}
return node;
}
public static void dijkstra(int[][] weight, int start) {
// 接受一个有向图的权重矩阵,和一个起点编号start(从0编号,顶点存在数组中)
// 返回一个int[] 数组shortPath,表示从start到它的最短路径长度
int n = weight.length; // 顶点(0,1,2,3,4)
//S的作用是记录已求出最短路径的顶点集合
int[] s = new int[n];
//U则是记录还未求出最短路径的顶点集合
List<Integer> u= new ArrayList<Integer>();
for (int i=0;i<n;i++) {
u.add(i);
}
// 保存start到其他各点最短路径的字符串表示
String[] path = new String[n];
for (int i = 0; i < n; i++){
path[i] = new String(getNode(start) + "-->" + getNode(i));//默认设置起点到各个顶点的输出格式
}
// 初始化,第一个顶点已经求出
s[start] = 0;
//U中排除第一个顶点
u.remove(Integer.valueOf(start));
for (int count = 1; count < n; count++) { // 要加入n-1个顶点
int k = -1; // 选出一个距离初始顶点start最近的未标记顶点
int dmin = Integer.MAX_VALUE;
//选择集合中未标记过的最短路径的节点(相当于在U中获取最小路径的节点)
for (int i = 0; i < n; i++) {
if (u.contains(i) && weight[start][i] < dmin) {
dmin = weight[start][i];
k = i;
}
}
// 将选出的最短路径节点放到集合S中,并设置该节点的路径大小
s[k] = dmin;
u.remove(Integer.valueOf(k));//排除以放到S集合的节点
// 以k为中间点,修正从start到未访问各点的距离
for (int i = 0; i < n; i++) {//和所有没有标记最短路径进行对比,更新U中的所有最短距离
//如果 '起始点到当前点距离' + '当前点到某点距离' < '起始点到某点距离', 则更新
if (u.contains(i) && weight[start][k] + weight[k][i] < weight[start][i]) {
weight[start][i] = weight[start][k] + weight[k][i];//修正起始节点到某点的最短距离
path[i] = path[k] + "-->" + getNode(i);//
}
}
}
//输出
for (int i = 0; i < n; i++) {
System.out.println("从" + getNode(start) + "出发到" + getNode(i) + "最短距离为:"+s[i]+",最短路径为:" + path[i]);
}
}
}
结果
从A出发到A最短距离为:0,最短路径为:A-->A
从A出发到B最短距离为:3,最短路径为:A-->D-->B
从A出发到C最短距离为:3,最短路径为:A-->D-->C
从A出发到D最短距离为:2,最短路径为:A-->D
从A出发到E最短距离为:6,最短路径为:A-->D-->C-->E