弗洛伊德(Floyd)算法之两点之间的最短距离问题

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.代码运行的最终结果(点击放大查看)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章