运行效果如下
源代码如图,注释已经很多了,如果还有点偏差的话可以看《大话数据结构》的迪杰斯特拉讲解部分
package algorithm.DataStruct.Frequentlyused.ShortestPath.Dijkstra;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
/**
* @author: Serendipity
* Date: 2022/2/16 20:37
* Description:迪杰斯特拉算法用于求最短路径问题
* 例如两个点,如何到达能采与最短的路径 底层使用广度优先BFS
* 迪杰斯特拉(Dijkstra)算法过程
* 设置出发顶点为v,顶点集合V{v1,v2,vi...},v到v中各顶点的距离构成距离集合Dis,Dis{d1,d2,di...},
* Dis集合记录着v到图中各顶点的距离(到自身可以看作0, v到vi距离对应为di)
* 1)从Dis中选择值最小的di并移出Dis集合,同时移出V集合中对应的顶点vi,此时的
* v到vi即为最短路径
* 2)更新Dis集合,更新规则为:比较v到V集合中顶点的距离值,与v通过vi到V集合
* 中顶点的距离值,保留值较小的一个(同时也应该更新顶点的前驱节点为vi,表明是通过vi到达的)
* 3)重复执行两步骤,直到最短路径顶点为目标顶点即可结束
*/
public class Dijkstra {
public static void main(String[] args) {
char[] vertex = {'0', '1', '2', '3', '4', '5', '6', '7', '8'};
//邻接矩阵
int[][] matrix = new int[vertex.length][vertex.length];
final int N = 65535;// 表示不可以连接
matrix[0] = new int[]{0, 1, 5, N, N, N, N, N, N};
matrix[1] = new int[]{1, 0, 3, 7, 5, N, N, N, N};
matrix[2] = new int[]{5, 3, 0, N, 1, 7, N, N, N};
matrix[3] = new int[]{N, 7, N, 0, 2, N, 3, N, N};
matrix[4] = new int[]{N, 5, 1, 2, 0, 3, 6, 9, N};
matrix[5] = new int[]{N, N, 7, N, 3, 0, N, 5, N};
matrix[6] = new int[]{N, N, N, 3, 6, N, 0, 2, 7};
matrix[7] = new int[]{N, N, N, N, 9, 5, 2, 0, 4};
matrix[8] = new int[]{N, N, N, N, N, N, 7, 0, 4};
//创建 Graph对象
Graph graph = new Graph(vertex, matrix);
//测试, 看看图的邻接矩阵是否ok
graph.showMatrix();
graph.Dijkstra_ShortestPath(0);
graph.showShortPathTable();
graph.showShortPathMatrix();
graph.showToShortestPath();
}
}
//图类
class Graph {
private char[] vertex;
private int[][] matrix;
private int[] ShortestPathMatrix; //用于存储最短路径下标的数组 [0,0,1,2]->表示0->0自己到自己 1->表示从0直接到1最近
private int[] ShortestWeightTable; //用于存储到各店最短路径的权值和 //2表示从1到更近,然后1由0直接到 所以2的路径为0->1->2
public Graph(char[] vertex, int[][] matrix) {
this.matrix = matrix;
this.vertex = vertex;
ShortestPathMatrix = new int[vertex.length];
ShortestWeightTable = new int[vertex.length];
}
/**
* 显示矩阵
*/
public void showMatrix() {
System.out.println("各顶点间关系权值图如下:");
for (int[] ints : this.matrix) {
System.out.println(Arrays.toString(ints));
}
}
public void showShortPathTable() {
System.out.print("到达各点的路径为:");
System.out.println(Arrays.toString(ShortestWeightTable));
}
public void showShortPathMatrix() {
System.out.print("到达各点的权值为:");
System.out.println(Arrays.toString(ShortestPathMatrix));
}
/**
* 该函数用于显示到达每一个顶点的路径
* 路径用每一个顶点再数组中的下标表示
* 例如第一个数据'0'的下标就是0以此类推
*/
public void showToShortestPath() {
HashMap<Character, ArrayList<String>> map = new HashMap<>();
for (int i = 0; i < vertex.length; i++) {//遍历所有的顶点
ArrayList<String> list = new ArrayList<>();//创建一个用于存放路径的List
getList(i,list);//向顶点中添加路过的顶点
Collections.reverse(list);//反转顶点 这是由于添加是倒序添加的
map.put((char)(i+48),list);//这个随意写 为了好看而已
}
int index=0;
for (Character character : map.keySet()) {//输出
System.out.println("到达v"+character+"的最短路径是"+map.get(character)
+"其权值为"+ShortestWeightTable[index++]);
}
}
/**
* 使用递归的方法向list中添加顶点所路过的顶点
* @param start 开始顶点对应的数组下标
* @param list 需要添加路径的list集合
*/
public void getList(int start,ArrayList<String>list){
if(start==0){ //遇到开始顶点0直接退出并且加入开始顶点
list.add(vertex[0]+""); //添加起始路径0
return; //已经到达源点 那么退出
}else{
list.add(vertex[start]+""); //不是源点 那么把当前路径添加到list中
getList(ShortestPathMatrix[start],list); //然后继续递归添加
}
}
public void Dijkstra_ShortestPath(int startVertex) {
int v, w, k = 0, min;
boolean isFind[] = new boolean[vertex.length];//定义已经找到最短路径的顶点数组
isFind[startVertex] = true;//开始的顶点那么直接就是最短路径0
for (v = 0; v < vertex.length; v++) {//初始化与初始移动的顶点连接的边的权值
ShortestWeightTable[v] = this.matrix[startVertex][v];//初始化权值之后才能决定如何从起始点往那个位置出发
} //这个数组记录源点到某个顶点的最小距离
ShortestWeightTable[startVertex] = 0; //开始顶点到开始顶点的距离为0
//每次循环球的起始顶点与一个顶点的最短路径由于抛去了起始顶点,因此v从1开始
for (v = 1; v < this.vertex.length; v++) {//遍历所有顶点 求得开始顶点到每个顶点的最短距离
min = Integer.MAX_VALUE;//暂时设置为MAX便于得到更小的值
for (w = 0; w < vertex.length; w++) {
if (!isFind[w] && ShortestWeightTable[w] < min) {//最小距离数组的数据<min上一次的最小数据
k = w; //那么就把当前更小的数据的位置记录 k用于记录这一次循环中得到的最小的数据
min = ShortestWeightTable[w];//w顶点对应的权值离开始顶点更近
}
}
isFind[k] = true;//找到最短路径,设置为true
for (w = 0; w < vertex.length; w++) {
//如果经过v顶点的路径比经过现在这条更短的话
//这一步算法的意思是先判断当前顶点是否已经有了最短路径,如果没有
//由于k是刚才新找到的已经得到最短路径的顶点对应的下标
//因此min+this.matrix[k][w]表示的是基于上一个顶点走到这个顶点距离更短
//还是从顶点直接走到她更短
//举个例子 例如v0->v1=1,v0->v2=5,v1->v2=3,那么明显v0->v1->v2=4<5
//因此我们从这个新节点(v1)走到这个v2距离更短
//那么我们就应该选择这条路加进去,而下面这个if判断就是怎么做的
//他先判断v2顶点还没找到最短路径,那么我们就试着通过v1->v2(this.matrix[k][w])+v0->v1(min)
//判断它是不是小于目前到达这个顶点的路径长度 如果是那么我们就更新
if (!isFind[w] && (min + this.matrix[k][w] < ShortestWeightTable[w])) {
//找到了更短的路径,修改
ShortestWeightTable[w] = min + this.matrix[k][w];
ShortestPathMatrix[w] = k; //说明到达这个顶点通过k这个顶点会更快
}
}
}
}
}