迪杰斯特拉算法是用来求解从带权连通图中某一顶点出发到其他各个顶点的最短距离(图的广度优先遍历).
大体实现步骤:
- 根据维护一个已访问顶点的集合的示例(包括:各个顶点是否已访问的数组,各个顶点的前驱节点的数组,从出发顶点到各个顶点的最短路径的数组)
- 更新出发顶点到周围各个顶点的最短距离和周围顶点的前驱节点的数据(调用VisitedVertex的update()方法).
- 循环找到新的访问节点(updateArr()方法返回的数据)更新新的访问节点到其周围顶点的最短距离和周围顶点的前驱节点的数据(在循环中调用VisitedVertex的update()方法).
连通图如下:
实现代码:
import java.util.Arrays;
public class DijkstraDemo {
public static final int N =1000000;// 表示顶点间不连通
public static final int VISITED_VALUE =1;// 表示顶点已访问
public static final int SELF_PATH =0;// 表示顶点和自己的距离
public static void main(String[] args) {
char[] vertex = { 'A', 'B', 'C', 'D', 'E', 'F', 'G' };
//邻接矩阵
int[][] matrix = new int[vertex.length][vertex.length];
matrix[0]=new int[]{N,5,7,N,N,N,2};
matrix[1]=new int[]{5,N,N,9,N,N,3};
matrix[2]=new int[]{7,N,N,N,8,N,N};
matrix[3]=new int[]{N,9,N,N,N,4,N};
matrix[4]=new int[]{N,N,8,N,N,5,4};
matrix[5]=new int[]{N,N,N,4,5,N,6};
matrix[6]=new int[]{2,3,N,N,4,6,N};
//创建 Graph对象
Graph graph = new Graph(vertex, matrix);
graph.dijkstra(6);
}
}
/**
* 图
*/
class Graph {
private char[] vertex; // 顶点数组
private int[][] matrix; // 邻接矩阵
private VisitedVertex vv; //已经访问的顶点的集合
public Graph(char[] vertex, int[][] matrix) {
this.vertex = vertex;
this.matrix = matrix;
}
/**
* 显示迪杰斯特拉算法结果
*/
public void showDijkstra(char[] vertex,int startIndex){
this.vv.show(vertex,startIndex);
}
/**
* 显示图
*/
public void showGraph(){
for (int[] link : this.matrix) {
System.out.println(Arrays.toString(link));
}
}
public void dijkstra(int startIndex) {
int len = this.vertex.length;
this.vv = new VisitedVertex(len, startIndex);
update(startIndex);// 更新出发顶点到周围顶点的最小距离和前驱节点数据
for (int i = 1; i < len; i++) {
int index = this.vv.updateArr();// 更新其他顶点到周围顶点的最小距离和前驱节点数据
update(index);
}
// 显示最短路径结果
this.showDijkstra(this.vertex,startIndex);
}
/**
* 更新index下标顶点到周围顶点的距离和周围顶点的前驱顶点
* @param index
*/
private void update(int index) {
int range,// 距离
length=this.matrix[index].length;// 邻接矩阵对应的index行的长度
for (int i = 0; i < length; i++) {
// 出发顶点到顶点i的距离(就是出发顶点到index的距离+顶点index到顶点i的距离的和)
range = this.vv.getDis(index) + this.matrix[index][i];
if (!this.vv.ifVisited(i) && range < this.vv.getDis(i)) {
// 更新数据
this.vv.updateDis(i,range);// 更新出发顶点到顶点i的最小距离
this.vv.updatePre(i, index);// 更新顶点i的前驱顶点为index
}
}
}
}
/**
* 已访问顶点的集合
*/
class VisitedVertex{
// 记录各个顶点是否访问过 1表示访问过,0未访问,会动态更新
public int[] already_arr;
// 每个下标对应的值为前一个顶点下标, 会动态更新
public int[] pre_visited;// 记录前驱节点的下标
// 记录出发顶点到其他所有顶点的距离,比如G为出发顶点,就会记录G到其它顶点的距离,会动态更新,求的最短距离就会存放到dis
public int[] dis;
/**
*
* @param length 节点数组的长度
* @param startIndex 开始节点的下标
*/
public VisitedVertex(int length,int startIndex) {
this.already_arr = new int[length];
this.pre_visited = new int[length];
this.dis = new int[length];
// 初始化最小距离数组,初始值为不连通的值
Arrays.fill(dis,DijkstraDemo.N);
already_arr[startIndex]=DijkstraDemo.VISITED_VALUE;// 标记开始节点已访问
dis[startIndex]=DijkstraDemo.SELF_PATH;// 开始节点到自己的距离为0
}
/**
* 功能: 判断index顶点是否被访问过
* @param index
* @return 如果访问过,就返回true, 否则访问false
*/
public boolean ifVisited(int index) {
return this.already_arr[index] == DijkstraDemo.VISITED_VALUE;
}
/**
* 功能: 更新出发顶点到index顶点的距离
* @param index
* @param length
*/
public void updateDis(int index, int length) {
this.dis[index]=length;
}
/**
* 功能: 更新index这个顶点的前驱顶点为pre顶点
* @param index
* @param pre
*/
public void updatePre(int index, int pre) {
this.pre_visited[index]=pre;
}
/**
* 功能:返回出发顶点到index顶点的距离
* @param index
*/
public int getDis(int index) {
return dis[index];
}
/**
* 继续选择并返回新的访问顶点, 比如这里的G 完后,就是 A点作为新的访问顶点(注意不是出发顶点)
* @return
*/
public int updateArr() {
int min = DijkstraDemo.N,index=0,len = this.already_arr.length;
for (int i = 0; i < len; i++) {
if (this.already_arr[i] != DijkstraDemo.VISITED_VALUE && this.dis[i] < min) {
min=this.dis[i];
index =i;
}
}
this.already_arr[index]=DijkstraDemo.VISITED_VALUE;
return index;
}
//显示最后的结果
//即将三个数组的情况输出
public void show(char[] vertex,int startIndex) {
System.out.println("节点访问情况:");
for(int i : already_arr) {
System.out.print(i + " ");
}
System.out.println();
System.out.println("前驱节点数据:");
for(int i : pre_visited) {
System.out.print(i + " ");
}
System.out.println();
System.out.println("最短距离数据:");
int length = vertex.length;
char startVertex = vertex[startIndex];
for (int i = 0; i < length; i++) {
System.out.println("从节点: "+startVertex+"到节点: "+vertex[i]+"的最短距离: "+this.dis[i]);
}
}
}
运行结果: