概述
- 迪杰斯特拉算法(Dijkstra`s algorithm)是最短路径算法, 用于计算一个节点到其它节点的最短路径. 它的主要特点是以起始点为中心向外层层扩展(广度优先搜索思想), 直到扩展到终点为止
最短路径问题
- 战争时期, 胜利乡有7个村庄(A,B,C,D,E,F,G), 现在有六个邮差, 从 G点出发, 需要分别把邮件分别送到 A,B,C,D,E,F,G六个村庄
- 各个村庄的距离用边线权值来表示, 比如 A-B距离5公里
- 计算出 G村庄到其它各个村庄的最短距离
- 代码实现
public class DijkstraAlgorithmApp {
/** 定义顶点*/
private static final char[] vertexes = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};
/** 定义常量, 9999表示某顶点间不连通*/
private static final int N = 9999;
public static void main(String[] args) {
/** 设置邻接矩阵的顶点与顶点间的边(附带权值)*/
int[][] matrix = new int[vertexes.length][vertexes.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 = new Graph(vertexes, matrix);
/** 打印邻接矩阵*/
graph.showGraph();
/** 求出最短路径*/
graph.dijkstra(2); // C
/** 打印结果*/
graph.showDijkstra();
}
}
class Graph {
/** 顶点个数*/
private char[] vertexes;
/** 邻接矩阵*/
private int[][] matrix;
/** 已访问过的顶点集合*/
private VisitedVertex visitedVertex;
public Graph(char[] vertexes, int[][] matrix) {
this.vertexes = vertexes;
this.matrix = matrix;
}
/** 打印邻接矩阵*/
public void showGraph() {
for (int[] link : matrix) {
System.out.println(Arrays.toString(link));
}
}
/** 打印结果*/
public void showDijkstra() {
visitedVertex.show();
}
/** 求出最短路径(通过迪杰斯特拉算法实现的)
* @param index 起始顶点下标*/
public void dijkstra(int index) {
visitedVertex = new VisitedVertex(vertexes, index);
/** 更新 index顶点到周围顶点的距离和前驱顶点*/
update(index);
for(int j = 1; j <vertexes.length; j++) {
/** 选择并返回新的访问顶点*/
index = visitedVertex.selectNewVertex();
/** 更新 index顶点到周围顶点的距离和前驱顶点*/
update(index);
}
}
/** 更新 index顶点到周围顶点的距离, 同时更新周围顶点的前驱顶点*/
private void update(int index) {
int distance = 0;
/** 按行遍历邻接矩阵*/
for(int j = 0; j < matrix[index].length; j++) {
/** 出发顶点到 index顶点的距离 + 从 index顶点到 j顶点的距离的和*/
distance = visitedVertex.getDistance(index) + matrix[index][j];
/** 当 j顶点未被访问过, 且 distance小于出发顶点到 j顶点的距离时*/
if(!visitedVertex.in(j) && distance < visitedVertex.getDistance(j)) {
/** 更新 j顶点的前驱顶点为 index*/
visitedVertex.updatePrecursor(j, index);
/** 更新出发顶点到 j顶点的距离*/
visitedVertex.updateDistance(j, distance);
}
}
}
}
/** 定义已访问过的顶点集合类*/
class VisitedVertex {
/** 定义顶点*/
public char[] vertexes;
/** 记录各个顶点是否被访问过 [1已访问, 0未访问], 会动态更新*/
public int[] already_visited;
/** 记录指定顶点的前驱顶点下标, 未访问和自己是0否则指定顶点下标, 会动态更新*/
public int[] pre_visited;
/** 记录出发顶点到其它所有顶点的最短距离(到自身为0), 会动态更新*/
public int[] distance;
/**
* @param vertexes: 顶点数组
* @param index: 起始顶点对应的下标, 比如指定 G顶点就是6*/
public VisitedVertex(char[] vertexes, int index) {
this.vertexes = vertexes;
this.already_visited = new int[vertexes.length];
this.pre_visited = new int[vertexes.length];
this.distance = new int[vertexes.length];
/** 初始化, 将 dis的所有元素填充 9999*/
Arrays.fill(distance, 9999);
/** 将起始顶点标记为已访问*/
this.already_visited[index] = 1;
/** 将起始顶点(自己), 距离设置为0*/
this.distance[index] = 0;
}
/** 判断指定顶点是否被访问过( index为顶点下标)*/
public boolean in(int index) {
return already_visited[index] == 1;
}
/** 更新出发顶点到指定顶点的距离( index为顶点下标)*/
public void updateDistance(int index, int distance) {
this.distance[index] = distance;
}
/** 更新 index顶点的前驱顶点为 preIndex*/
public void updatePrecursor(int index, int preIndex) {
pre_visited[index] = preIndex;
}
/** 返回出发顶点到 index顶点的距离*/
public int getDistance(int index) {
return distance[index];
}
/** 筛选出, 未被访问的顶点(权值最小的), 然后返回*/
public int selectNewVertex() {
int min = 9999, index = 0;
for(int i = 0; i < already_visited.length; i++) {
if(already_visited[i] == 0 && distance[i] < min) {
min = distance[i];
index = i;
}
}
/** 将 index顶点标记为已访问*/
already_visited[index] = 1;
return index;
}
/** 打印结果*/
public void show() {
System.out.println("------------------------------");
// 输出 already_visited
for(int i: already_visited) {
System.out.print(i + " ");
}
System.out.println();
// 输出 pre_visited
for(int i: pre_visited) {
System.out.print(i + " ");
}
System.out.println();
// 输出 distance
for(int i: distance) {
System.out.print(i + " ");
}
System.out.println();
int index = 0;
for(int i: distance) {
if (i != 9999) {
System.out.print(vertexes[index] + "(" + i + ") ");
} else {
System.out.println("N ");
}
index++;
}
System.out.println();
}
}
输出:
[9999, 5, 7, 9999, 9999, 9999, 2]
[5, 9999, 9999, 9, 9999, 9999, 3]
[7, 9999, 9999, 9999, 8, 9999, 9999]
[9999, 9, 9999, 9999, 9999, 4, 9999]
[9999, 9999, 8, 9999, 9999, 5, 4]
[9999, 9999, 9999, 4, 5, 9999, 6]
[2, 3, 9999, 9999, 4, 6, 9999]
------------------------------
1 1 1 1 1 1 1
2 0 0 5 2 4 0
7 12 0 17 8 13 9
A(7) B(12) C(0) D(17) E(8) F(13) G(9)
如果您觉得有帮助,欢迎点赞哦 ~ 谢谢!!