最短路径问题——Dijkstra算法+Bellmanford算法+Floyd算法
最短路径算法
- 1、Dijkstra算法
-
- 1.2 使用优先队列 优化 查找每轮中距离起点最近的节点下标`(推荐)`
- 2、BellmanFord算法
-
- 2.1 邻接表List\<Edge\>实现图的方式(稍微比邻接矩阵快一点)
- 2.2 邻接矩阵实现图的方式(优点像Floyd算法)`不推荐`
- 3、Floyd-Warshall算法
1、Dijkstra算法
原理:
1)每一次循环确定一个距离起点最短的节点的路径长度;
2)确定节点后,以它为中间点去更新与其相连的节点距离起点的路径长度;
准备:
1)路径图,int[][] graph;
2)节点是否使用过,boolean[] used;
3)节点距离起点的最短路径长度,int[] shortLen;
核心:两个判断条件
1)当前循环的最近节点判断:
1、未使用过;2、与起点间存在路径;3、小于其他节点到起点距离;
2)更新当前轮相邻节点距起点的最短路径长度判断:
1、未使用过;2、与index节点相连;3、更新后的距离小于之前达到起点的距离 或 还没有到达起点的路径;
public static void main(String[] args) {
//路径图
int[][] len = new int[2022][2022];
boolean[] used = new boolean[2022];
//起点到达每个节点的最短路径长度
int[] shortLen = new int[2022];
for(int i=1;i<2022;i++){
shortLen[i] = len[1][i];
}
used[1] = true;
//n个节点,要去寻找其他n-1个节点距离起点的最短路径长度,所以要遍历n-1次!!
for(int i=2;i<2022;i++){
//记录当前轮的最近未使用节点下标
int index = 0;
//记录当前轮的距离起点的最近未使用节点的路径长度
int min = Integer.MAX_VALUE;
//遍历最短路径节点,寻找当前轮未使用的最短路径长度及节点下标
for(int j=2;j<2022;j++){
if(!used[j] && shortLen[j]!=0 && min>shortLen[j]){
//条件:1、未使用过;2、与起点间存在路径;3、小于其他节点到起点距离;
min = shortLen[j];
index = j;
}
}
//找到最近节点后,将其标识为已使用
used[index] = true;
//根据标记的最近节点,将其作为中间节点,去重新更新其他与其相连但未使用节点的shortLen
for(int j=2;j<2022;j++){
if(!used[j] && len[index][j]!=0 && (len[index][j]+min < shortLen[j] || shortLen[j]==0)){
//条件:1、未使用过;2、与index节点相连;3、更新后的距离小于之前达到起点的距离 或 还没有到达起点的路径;
shortLen[j] = len[index][j] + min;
}
}
}
System.out.println(shortLen[2021]);
}
注意:
如果将不相连的节点路径设置为Integer.MAX_VALUE,则可以优化掉两个核心判断条件中的shortLen[j]!=0 和 shortLen[j]==0条件,
不足:
路径中不能包含负权重!
1.2 使用优先队列 优化 查找每轮中距离起点最近的节点下标(推荐)
public static void dijkstra(int[][] graph, int start) {
int n = graph.length; // 节点数量
int[] dist = new int[n]; // 存储从起点到各节点的最短距离
boolean[] visited = new boolean[n]; // 标记节点是否已被处理
// 初始化距离数组
Arrays.fill(dist, Integer.MAX_VALUE);
dist[start] = 0; // 起点到自身的距离为 0