原理(一定要理解参透)请参照上篇博客:
https://blog.csdn.net/qq_42789954/article/details/112531417
此篇文章只是在上篇文章代码上进行了些许优化,可读性以及演示效果更好。
图依然是上篇的图:
不多说,直接上代码。
1. 代码
import java.util.ArrayList;
import java.util.Scanner;
public class Dijkstra_MoreFun {
private final int num_of_nodes = 9; //定义图中节点个数
private int start;
private int end;
private int initial_start;
private int biggest;
private ArrayList<Integer> point_list;
private boolean[] visited;
private int[] cal_distance;
private int[] distance;
private int[] parent;
private int[][] graph;
public static void main(String[] args) {
Dijkstra_MoreFun dijkstra = new Dijkstra_MoreFun();
dijkstra.test();
}
private void test() {
//调用初始化方法进行初始化
initializer_parameter();
initializer_adjacent_matrix();
//对节点编号范围进行提示
System.out.println("节点编号范围为:" + 0 + "~" + (num_of_nodes - 1));
//调用设置起点与终点方法
set_start_point();
set_end_point();
distance[start] = 0;
while (point_list.size() != 1) {
if (end == start) {
System.out.println("起点与终点重合");
break;
}
update();
visited_remove(start);
int min_distance = find_min();
if (!estimate(min_distance)) {
break;
}
}
show_path();
}
//参数初始化程序
private void initializer_parameter() {
biggest = Integer.MAX_VALUE;
point_list = new ArrayList<>();
for (int i = 0; i < num_of_nodes; i++) {
//point_list.add(i);不能直接这样使用,必须要先在上面创建对象!!!
point_list.add(i);
}
visited = new boolean[]{false, false, false, false, false, false, false, false, false};
cal_distance = new int[9];
distance = new int[]{biggest, biggest, biggest, biggest, biggest, biggest, biggest, biggest, biggest};
parent = new int[]{-1, -1, -1, -1, -1, -1, -1, -1, -1};
}
//邻接矩阵初始化程序
private void initializer_adjacent_matrix() {
graph = new int[][]{
{0, 4, biggest, biggest, biggest, biggest, biggest, 8, biggest},
{4, 0, 8, biggest, biggest, biggest, biggest, 3, biggest},
{biggest, 8, 0, 7, biggest, 4, biggest, biggest, 2},
{biggest, biggest, 7, 0, 9, 14, biggest, biggest, biggest},
{biggest, biggest, biggest, 9, 0, 10, biggest, biggest, biggest},
{biggest, biggest, 4, 14, 10, 0, 2, biggest, biggest},
{biggest, biggest, biggest, biggest, biggest, 2, 0, 6, 6},
{8, 3, biggest, biggest, biggest, biggest, 6, 0, 1},
{biggest, biggest, 2, biggest, biggest, biggest, 6, 1, 0}
};
}
//设置起点编号,并校验合法性
private void set_start_point() {
System.out.println("请输入起点编号:");
Scanner sc = new Scanner(System.in);
start = sc.nextInt();
while (start < 0 || start > num_of_nodes - 1) {
System.out.println("输入的起点编号超出范围,请重新输入:");
start = sc.nextInt();
}
initial_start = start;
}
//设置终点编号,并校验合法性
private void set_end_point() {
System.out.println("请输入终点编号:");
Scanner sc = new Scanner(System.in);
end = sc.nextInt();
while (end < 0 || end > num_of_nodes - 1) {
System.out.println("输入的终点编号超出范围,请重新输入:");
end = sc.nextInt();
}
}
//更新 distance 和 parent 数组
private void update() {
for (Integer node : point_list) {
if (graph[start][node] != biggest) {
cal_distance[node] = graph[start][node] + distance[start];
if (cal_distance[node] < distance[node]) {
distance[node] = cal_distance[node];
parent[node] = start;
}
}
}
}
//从点集合中删除被搜索过的点
private void visited_remove(int searched) {
visited[start] = true;
point_list.remove(Integer.valueOf(searched));
}
//遍历 删除已经搜索过的点 的点集合,得到对应的编号
//再根据编号搜索 distance 集合中的最小值,得到最小值对应的节点编号,作为下一个等待搜索的点
private int find_min() {
int min = biggest;
for (Integer node : point_list) {
if (distance[node] < min) {
min = distance[node];
start = node;
}
}
return min;
}
//判断 min 与 start 的值
private boolean estimate(int min) {
if (min != biggest && start == end) {
//这种情况说明已经找到了到终点的路径,且这条路径还最短,可以结束搜索了
System.out.println("已经找到了最短路径,路径长度为:" + min + "。后续不再进行搜索");
return false;
} else if (min == biggest) {
//起点到其他节点间全为不可达,不论是到终点还是其它点,均不可达
//这种情况代表起点至终点无路径
System.out.println("起点至终点无路径");
return false;
} else {
return true;
}
}
//路径显示
private void show_path() {
System.out.print("路径为:");
System.out.print(end + " ← ");
//另外创建一个变量 initial_start,记录最初的 start 值
while (parent[end] != -1 && parent[end] != initial_start) {
System.out.print(parent[end] + " ← ");
end = parent[end];
}
System.out.print(initial_start);
}
}
2. 参数说明
private final int num_of_nodes = 9; //定义图中节点个数为9个
private int start; //定义起点编号(代表当前搜索节点,会发生变化)
private int end; //定义终点编号
private int initial_start; //定义最初的起点编号
private int biggest; //定义正无穷
private ArrayList<Integer> point_list; //定义节点集合
private boolean[] visited; //定义各个节点是否被搜索数组
private int[] cal_distance; //从最初起点到各个节点当前路径的距离(不一定最短)
private int[] distance; //最初起点到当前节点的最短距离数组
private int[] parent; //各个节点的父节点(用于路径展示)
private int[][] graph; //定义邻接矩阵