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.代碼運行的最終結果(點擊放大查看)