1.概述
(1)与迪杰斯特拉(Dijkstra)算法一样,弗洛伊德(Floyd)算法也是一种用于寻找给定的加权图中顶点间最短路径的算法,该算法
名称以创始人之一、1978 年图灵奖获得者、斯坦福大学计算机科学系教授罗伯特·弗洛伊德命名
2.弗洛伊德(Floyd)算法 与 迪杰斯特拉(Dijkstra)算法 的区别
(1) 弗洛伊德(Floyd)算法:图中的每一个顶点都是出发顶点,需要求出每一个被看成为出发顶点的顶点到其他顶点的最短路径
(2)迪杰斯特拉(Dijkstra)算法:选定图中某一个顶点作为出发顶点,求出出发顶点到其他顶点的最短路径
3.弗洛伊德(Floyd)算法基本思路
(1)设置 i 为出发顶点,k 为中间顶点,j 为其他顶点
(2)设置顶点 vi 到顶点 vk 的最短路径已知为 Lik,顶点 vk 到 vj 的最短路径已知为 Lkj,顶点 vi 到 vj 的路径为 Lij,则 vi 到 vj 的最短路径为:min((Lik+Lkj),Lij),vk 的取值为图中所有顶点,则可获得 vi 到 vj 的最短路径
(3)三层 for 循环解决问题
4.代码实现
package com.zzb.algorithm.floyd;
import java.io.Serializable;
import java.util.Arrays;
/**
* @Auther: Administrator
* @Date: 2020/3/30 14:46
* @Description: 弗洛伊德算法
*/
public class Floyd {
public static void main(String[] args) {
// 顶点值数组
String[] vertexArray = {"A", "B", "C", "D", "E", "F", "G"};
// 邻接矩阵
final int N = Integer.MAX_VALUE/2; // 表示不可以连接
int[][] matrix = new int[vertexArray.length][vertexArray.length];
matrix[0] = new int[] { 0, 5, 7, N, N, N, 2 };
matrix[1] = new int[] { 5, 0, N, 9, N, N, 3 };
matrix[2] = new int[] { 7, N, 0, N, 8, N, N };
matrix[3] = new int[] { N, 9, N, 0, N, 4, N };
matrix[4] = new int[] { N, N, 8, N, 0, 5, 4 };
matrix[5] = new int[] { N, N, N, 4, 5, 0, 6 };
matrix[6] = new int[] { 2, 3, N, N, 4, 6, 0 };
// 创建图对象
Graph graph = new Graph(vertexArray, matrix);
// 详细展示最短距离数据
graph.showDistanceDetail();
}
}
/**
* 图类
*/
class Graph implements Serializable {
private static final long serialVersionUID = -4402590218398745596L;
// 存储图中各个顶点的集合
private String[] vertexArray;
// 存储图中各条边的邻接矩阵,也作为保存各个顶点作为出发顶点到其他顶点的最短距离的数组
private int[][] edgeArray;
// 存储各个顶点的前驱顶点,即通过哪个顶点到达该顶点
private int[][] pre;
/**
* 构造器初始化
* @param vertexArray 顶点集合
* @param edgeArray 边集合
*/
public Graph(String[] vertexArray, int[][] edgeArray) {
this.vertexArray = vertexArray;
this.edgeArray = edgeArray;
// 初始化其他顶点的前驱顶点
// A->A,A->B,A->C,A->D,A->E,A->F,A->G
// A,B,C,D,E,F,G 的前驱顶点都初始化为A
// B->A,B->B,B->C,B->D,B->E,B->F,B->G
// A,B,C,D,E,F,G 的前驱顶点都初始化为B
// ...如此类推,用对应索引 i 来表示前驱顶点
this.pre = new int[this.edgeArray.length][this.edgeArray[0].length];
for(int i = 0; i < this.vertexArray.length; i++) {
Arrays.fill(pre[i],i);
}
}
/**
* 弗洛伊德算法
*/
private void floyd() {
// 中间顶点
for(int k = 0; k < this.vertexArray.length; k++) {
// 被看成为出发点的每一个顶点
for(int i = 0; i < this.vertexArray.length; i++) {
// 其他顶点
for(int j = 0; j < this.vertexArray.length; j++) {
if(this.edgeArray[i][k] + this.edgeArray[k][j] < this.edgeArray[i][j]) {
// 更新出发点到其他顶点的最短距离
this.edgeArray[i][j] = this.edgeArray[i][k] + this.edgeArray[k][j];
// 更新 j 的前驱顶点
this.pre[i][j] = this.pre[k][j];
}
}
}
}
}
/**
* 详细展示最短距离数据
*/
public void showDistanceDetail() {
// 弗洛伊德算法
floyd();
// 后续处理,详细展示最短距离数据
int tempIndex;
String tempStr = "";
// 最短距离数组
for(int i = 0; i < this.vertexArray.length; i++) {
for(int j = 0; j < this.vertexArray.length; j++) {
// 比如,A(i)->D(j) 的最短距离所走过的顶点分析,看上面的图来分析,如下:
// (1)找到A(i)->D(j)的前驱为F(5),pre[i][tempIndex] == 5,
// (2)再找A(i)->F(5)的前驱为G(6),pre[i][tempIndex] == 6,
// (3)再找到A(i)->G(6)前驱为A(i),pre[i][tempIndex] == 1,
// (4)前驱为 i(即出发顶点的下标索引) ,终止路径寻找,得到两点之间最短距离所走过的顶点
tempIndex = j;
while(this.pre[i][tempIndex] != i) {
tempIndex = this.pre[i][tempIndex];
tempStr = this.vertexArray[tempIndex] + "->" + tempStr;
}
// 拼接
tempStr = this.vertexArray[i] + "->" + tempStr + this.vertexArray[j];
System.out.print(this.vertexArray[i] + "到" + this.vertexArray[j] + "的最短距离为" + this.edgeArray[i][j]
+ "(" + tempStr + ")" + "\t\t\t\t" + "| ");
// 清空
tempStr = "";
}
System.out.println();
}
}
}
5.代码运行的最终结果(点击放大查看)