【数据结构与算法】弗洛伊德(Floyd)算法

一,基本介绍

在这里插入图片描述

1)和Dijkstra算法一样,弗洛伊德(Floyd)算法也是一种用于寻找给定的加权图中顶点最短路径的算法。该算法名称一创始人之一,1978年图灵奖获得者,斯坦福大学计算机科学系教授罗伯特.弗洛伊德命名;
2)弗洛伊德算法(Floyd)计算图中各个顶点之间的最短路径;
3)迪杰斯特拉算法用于计算图中某一个顶点到其他顶点的最短路径;
4)弗洛伊德算法VS迪杰斯特拉算法:迪杰斯特拉算法通过选定的被访问顶点,求出从出发访问顶点到其他顶点的最短路径;弗洛伊德算法中每一个顶点都是出发访问点,所以需要将每一个顶点看做被访问顶点,求出从每一个顶点到其他顶点的最短路径。

二,思路分析

1)设置顶点vi到顶点vk的最短路径为Lik,顶点vk到顶点vj的最短路径已知为Lkj,顶点vi到vj的路径为Lij,则vi到vj的最短路径为:min((Lik + Lkj),Lij),vk的取值为图中所有顶点,则可以获得vi到vj的最短路径;
2)至于vi到vk的最短路径Lik或者vk到vj

三,思路图解

创建距离表,存放两个点之间的最短距离
前驱关系表,存放两个点之间的中间点,默认是本身
在这里插入图片描述
这里N表示很大的数,表示两个点距离大到一定程度我们就可以把他当作没有路;
初始顶点前驱顶点都指向自己。
1)第一轮循环中,以A(下标为:0)作为中间顶点【即把A作为中间顶点的所有情况都进行遍历,就会更新距离表和前驱关系】,距离表和前驱关系更新为:
以A作为中间顶点的有(无向图,不考虑方向):
B - A - C [5 + 7 = 12] < B - C [N] => B - C [12] 修改距离
B - A - G [5 + 2 = 7] > B - G[4] 不修改距离
C - A - G [7 + 2 = 9] < C - G[N] => C - G [9] 修改距离
注意,这里C到A,B到A,A到G的距离不一定是直接连接,如果B - G - A如果连通,也算为这里的 B - A
更新后为:
在这里插入图片描述

在这里插入图片描述

这里B - C 就连通了,C - G也连通了,就可以作为下面循环的一个条件。
2)第二轮循环中,以B(下标为:1)作为中间顶点【即把B作为中间顶点的所有情况都进行遍历,就会更新距离表和前驱关系】,距离表和前驱关系更新为:
以B作为中间顶点的有(无向图,不考虑方向):
A - B - D [5 + 9 =14] < A - D [N] => A - D [14]
A - B - G [5 + 4 = 9] > A - G [2]
C - B - D [12 + 9 = 21] < C - D [N] => C - D [21]
C - B - G [12 + 4 = 16] > C - G [9]
D - B - G [9 + 4 = 13] < D - G [N] => D - G [13]
更新后为:
在这里插入图片描述

在这里插入图片描述

3)第三轮循环中,以C(下标为:2)作为中间顶点【即把C作为中间顶点的所有情况都进行遍历,就会更新距离表和前驱关系】,距离表和前驱关系更新为:
以C作为中间顶点的有(无向图,不考虑方向):
A - C - B [7 + 12 = 19] > A - B [5]
A - C - D [7 + 21 = 28] > A - D [13]
A - C - E [7 + 8 = 15] < A - E [N] => A - E [15]
A - C - G [7 + 9 = 16] > A - G [2]
B - C - D [12 + 21 = 33] > B - D [9]
B - C - E [12 + 8 = 20] < B - E [N] => B - E [20]
B - C - G [12 + 9 = 21] > B - G [4]
D - C - E [21 + 8 = 29] < D - E [N] => D- E [29]
D - C - G [21 + 9 = 30] > D - G [13]
E - C - G [8 + 9 = 17] > E - G [4]
更新后为:
在这里插入图片描述

在这里插入图片描述

4)第四轮循环中,以D(下标为:3)作为中间顶点【即把D作为中间顶点的所有情况都进行遍历,就会更新距离表和前驱关系】,距离表和前驱关系更新为:
以D作为中间顶点的有(无向图,不考虑方向):
A - D - B [14 + 9 = 23] > A - B [5]
A - D - C [14 + 21 = 35] > A - C [7]
A - D - E [14 + 29 = 43] > A - E [15]
A - D - F [14 + 4 = 18] < A - F[N] => A - F[18]
A - D - G [14 + 13 = 27] > A - G [2]
B - D - C [9 + 21 = 30] > B - C [12]
B - D - E [9 + 29 = 38] > B - D [20]
B - D - F [9 + 4 = 13] > B - F [N] => B - F [13]
B - D - G [9 + 13 = 22] > B - G [4]
C - D - E [21 + 29 = 50] > C - E [8]
C - D - F [21 + 4 = 25] < C - F [N] => C - F [25]
C - D - G [21 + 13 = 34] > C - G [9]
E - D - F [29 + 4 = 33] > E - F [5]
E - D - G [29 + 13 = 42] > E - G [4]
F - D - G [4 + 13 = 17] > F - G [6]
更新后为:
在这里插入图片描述

在这里插入图片描述

5)第五轮循环中,以E(下标为:4)作为中间顶点【即把E作为中间顶点的所有情况都进行遍历,就会更新距离表和前驱关系】,距离表和前驱关系更新为:
以E作为中间顶点的有(无向图,不考虑方向):
A - E - B [15 + 20 = 35] > A - B [5]
A - E - C [15 + 8 = 23] > A - C [7]
A - E - D [15 + 29 = 44] > A - D [14]
A - E - F [15 + 5 = 20] > A - F [18]
A - E - G [15 + 4 = 19] > A - G [20]
B - E - C [20 + 8 = 28] > B - C [12]
B - E - D [20 + 29 = 49] > B - D [9]
B - E - F [20 + 5 = 25] > B - F [13]
B - E - G [20 + 4 = 24] > B - G [4]
C - E - D [8 + 29 = 37] > C - D [21]
C - E - F [8 + 5 = 13] < C - F [25] => C - F [13]
C - E - G [8 + 4 = 12] > C - G [9]
D - E - F [29 + 5 = 34] > D - F [4]
D - E - G [29 + 4 = 33] > D - G [13]
F - E - G [5 + 4 = 9] > F - G [6]
更新后为:
在这里插入图片描述

在这里插入图片描述
6)第六轮循环中,以F(下标为:5)作为中间顶点【即把E作为中间顶点的所有情况都进行遍历,就会更新距离表和前驱关系】,距离表和前驱关系更新为:
以F作为中间顶点的有(无向图,不考虑方向):
A - F - B [18 + 13 = 31] > A - B [5]
A - F - C [18 + 13 = 31] > A - C [7]
A - F - D [18 + 4 = 22] > A - D [14]
A - F - E [18 + 5 = 23] > A - E [15]
A - F - G [18 + 6 = 24] > A - G [2]
B - F - C [13 + 13 = 26] > B - C [12]
B - F - D [13 + 4 = 17] > B - D [9]
B - F - E [13 + 5 = 18] < B - E [20] = > B - E [18]
B - F - G [13 + 6 = 19] > B - G [4]
C - F - D [13 + 4 = 17] < C - D [21] => C - D [17]
C - F - E [13 + 5 = 18] > C - E [8]
C - F - G [13 + 6 = 19] > C - G [9]
D - F - E [4 + 5 = 9] < D - E [29] => D - E [9]
D - F - G [4 + 6 = 10] < D - G [13] => D - G [10]
E - F - G [5 + 6 = 11] > E - G [4]
更新后为:
在这里插入图片描述
在这里插入图片描述
7)第七轮循环中,以G(下标为:6)作为中间顶点【即把E作为中间顶点的所有情况都进行遍历,就会更新距离表和前驱关系】,距离表和前驱关系更新为:
以G作为中间顶点的有(无向图,不考虑方向):
A - G - B [2 + 4 = 6] > A - B [5]
A - G - C [2 + 9 = 11] > A - C [7]
A - G - D [2 + 10 = 12] < A - D [14] => A - D [12]
A - G - E [2 + 4 = 6] < A - E [15] => A - E [6]
A - G - F [2 + 6 = 8] < A - F [17] => A - F [8]
B - G - C [4 + 9 = 13] > B - C [12]
B - G - D [4 + 10 = 14] > B - D [9]
B - G - E [4 + 4 = 8] < B - E [18] => B - E [8]
B - G - F [4 + 6 = 10] < B - F [13] => B - F [10]
C - G - D [9 + 10 = 19] > C - D [17]
C - G - E [9 + 4 = 13] > C - E [8]
C - G - F [9 + 6 = 15] > C - F [15]
D - G - E [10 + 4 = 14] > D - E [9]
D - G - F [10 + 6 = 16] > D - F [4]
E - G - F [4 + 6 = 10] > E - F [5]
更新后为:
在这里插入图片描述
在这里插入图片描述

四,代码实现

package com.algorithm.floyd;

import java.util.Arrays;

public class FloydAlgorithm {
    public static void main(String[] args) {
        char[] vertex = {'A','B','C','D','E','F','G'};
        final int N = 65536;
        //创建邻接矩阵
        int[][] matrix = new int[][]{
                {0,5,7,N,N,N,2},
                {5,0,N,9,N,N,4},
                {7,N,0,N,8,N,N},
                {N,9,N,0,N,4,N},
                {N,N,8,N,0,5,4},
                {N,N,N,4,5,0,6},
                {2,4,N,N,4,6,0}
        };
        //创建Graph对象
        Graph graph = new Graph(vertex.length,matrix,vertex);
        graph.floyd();
        graph.show();
    }
}
//创建图
class Graph {
    private char[] vertex; //存放顶点的数组
    private int[][] dis; //存放从各个顶点出发到其他顶点的距离,最后的结果,也是保留在该数组
    private int[][] pre; //保存到达目标顶点的前驱顶点
    //构造器

    /**
     *
     * @param length 大小
     * @param matrix 邻接矩阵
     * @param vertex 顶点数组
     */
    public Graph(int length,int[][] matrix,char[] vertex) {
        this.vertex = vertex;
        this.dis = matrix;
        this.pre = new int[length][length];
        //存放的是前驱顶点的下标
        for (int i = 0;i < length;i++) {
            Arrays.fill(pre[i],i);
        }

    }
    //显示pre数组和dis数组
    public void show() {
        for (int k = 0;k < dis.length;k++) {
            //先将pre数组输出的一行
            for (int i = 0;i < dis.length;i++) {
                System.out.print(vertex[pre[k][i]] + " ");
            }
            System.out.println();
            //输出dis数组的一行数据
            for (int i = 0;i < dis.length;i++) {
                System.out.print("(" + vertex[k] + "到" + vertex[i] + "的最短路径是" + dis[k][i] + ") ");
            }
            System.out.println();
        }
    }
    //弗洛伊德算法
    public void floyd() {
        int len = 0; //变量保存距离
        //对中间顶点的遍历,k就是中间的顶点的下标
        for (int k = 0;k < dis.length;k++) {
            //从i顶点开始出发[A,B,C,D,E,F,G],做后继节点/前驱节点
            for (int i = 0;i < dis.length;i++) {
                //到达j顶点[A,B,C,D,E,F,G],做前驱节点/后继节点
                for (int j = 0;j < dis.length;j++) {
                    len = dis[i][k] + dis[k][j]; // => 求出从i顶点出发,经过k中间顶点,到达j的顶点距离
                    if (len < dis[i][j]) { //如果len小于dis[i][j]
                        dis[i][j] = len; //更新距离
                        pre[i][j] = pre[k][j]; //更新前驱顶点
                    }
                }
            }
        }
    }
}

五,运行结果

在这里插入图片描述
与我们设想的一致,所以代码正确。

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值