前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >数据结构(十三):最短路径(Floyd算法)

数据结构(十三):最短路径(Floyd算法)

作者头像
zhipingChen
发布2018-12-14 11:19:43
1.6K0
发布2018-12-14 11:19:43
举报
文章被收录于专栏:编程理解编程理解

Bellman-Ford 算法或者 Dijkstra 算法用于解决单源最短路径问题,获取从指定起点出发,到达图中各个顶点的最短路径。若要获得图中每两个顶点之间的最短路径,则需要对算法执行

次,不过这里推荐另一种获得每对顶点间最短路径的方式。

Floyd-Warshall 算法使用动态规划策略计算图中每两个顶点间的最短路径,算法中通过调整路径中经过的中间顶点来缩小路径权值,最终得到每对顶点间的最短路径。

Floyd 算法允许图中存在负权边,但是不能存在负权回路。

算法介绍

对于图

,以

表示顶点集合,则从顶点

到顶点

的最短路径中经过的所有顶点都处于集合

中。对于顶点集合

,不妨以

表示从顶点

到顶点

的最短路径权值,且路径中经过的顶点都处于集合

中。因此当

时,因为此时的最短路径并非基于全部顶点集合,所以此时的

值可能要大于

。当

时,则有

,即此时的最短路径才是基于顶点集合

上真正的最短路径权值。

根据最短路径的特性,若从顶点

到顶点

的最短路径为

,则路径

为顶点

到顶点

的最短路径,因为若

之间存在权值更小的路径,则顶点

的最短路径

不成立,同理,路径

为顶点

到顶点

的最短路径。

对于顶点集合

,若顶点

到顶点

的最短路径中不包含顶点

,则有

;若最短路径中包含顶点

,则有

。若

,则

,表示顶点

和顶点

之间的路径上不存在其他顶点,路径权值即为边权值。

因此有如下递推关系式:

算法过程

根据该递推关系可知,对于任意两个顶点

,可以递增

值来逐渐获得最终的最短路径权值

。所以在算法的实现中,可以设置一个

二维矩阵,用于保存每两个顶点之间的路径权值,递增

值,遍历更新矩阵每个元素的路劲权值,当

时,此时矩阵中存储的则是任意顶点

之间的最短路径权值。

演示示例

graph

matrix

根据图 graph 构造矩阵 matrix,其中顶点到自身的距离为 0,每两个顶点之间边的权值如 matrix 所示。

时,根据推导关系式

遍历更新矩阵元素,更新后,矩阵如下图所示:

matrix_1

随便元素值并没有发生变化,但此时对于任意顶点

,矩阵 matrix_1 中存储的都是

的值,表示任意两个顶点在中间顶点处于集合

上的最短路径权值。

递增

值,当

时,矩阵元素如下图所示:

matrix_8

此时矩阵 matrix_9 中存储的都是

的值,表示任意两个顶点在中间顶点处于集合

上的最短路径权值,即此时对于任意两个顶点有

算法示例

代码语言:javascript
复制
def floyd(graph):
    matrix = graph.list
    for k in range(graph.number):
        for i in range(graph.number-1,-1,-1):
            for j in range(graph.number):
                if matrix[i][k] != None and matrix[k][j] != None and (matrix[i][j] == None or matrix[i][k] + matrix[k][j] < matrix[i][j]):
                    matrix[i][j] = matrix[i][k] + matrix[k][j]

floyd 算法较为简洁,代码中存在三层循环,第二层和第三层循环为遍历矩阵每个元素,根据递推关系式,更新每两个顶点之间的路径权值。第一层循环则是递增

值,直到

,此时更新矩阵元素,可以获得基于整个顶点集合上的最短路径权值。

性能分析

floyd 算法中存在三层循环,所以时间复杂度为

代码附录

代码语言:javascript
复制
from adjacencyMatrix import AdjacencyMatrix

# representing shortest path for each vertex
def floyd(graph):
    matrix = graph.list
    for k in range(graph.number):
        for i in range(graph.number-1,-1,-1):
            for j in range(graph.number):
                if matrix[i][k] != None and matrix[k][j] != None and (matrix[i][j] == None or matrix[i][k] + matrix[k][j] < matrix[i][j]):
                    matrix[i][j] = matrix[i][k] + matrix[k][j]

def show(graph):
    for i in range(graph.number):
        print('node', (i + 1), 'distance:', end = ' ')
        j = 0
        while j < graph.number:
            print(graph.list[i][j], end = ' ')
            j += 1
        print()

if __name__ == '__main__':
    graph = AdjacencyMatrix(9)
    graph.insert(1, 1, 0)
    graph.insert(1, 2, 4)
    graph.insert(1, 8, 8)
    graph.insert(2, 1, 4)
    graph.insert(2, 2, 0)
    graph.insert(2, 3, 8)
    graph.insert(2, 8, 11)
    graph.insert(3, 2, 8)
    graph.insert(3, 3, 0)
    graph.insert(3, 4, 7)
    graph.insert(3, 6, 4)
    graph.insert(3, 9, 2)
    graph.insert(4, 3, 7)
    graph.insert(4, 4, 0)
    graph.insert(4, 5, 9)
    graph.insert(4, 6, 14)
    graph.insert(5, 4, 9)
    graph.insert(5, 5, 0)
    graph.insert(5, 6, 10)
    graph.insert(6, 3, 4)
    graph.insert(6, 4, 14)
    graph.insert(6, 5, 10)
    graph.insert(6, 6, 0)
    graph.insert(6, 7, 2)
    graph.insert(7, 6, 2)
    graph.insert(7, 7, 0)
    graph.insert(7, 8, 1)
    graph.insert(7, 9, 6)
    graph.insert(8, 1, 8)
    graph.insert(8, 2, 11)
    graph.insert(8, 7, 1)
    graph.insert(8, 8, 0)
    graph.insert(8, 9, 7)
    graph.insert(9, 3, 2)
    graph.insert(9, 7, 6)
    graph.insert(9, 8, 7)
    graph.insert(9, 9, 0)
    floyd(graph)
    show(graph)
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018.11.18 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 算法介绍
  • 算法过程
  • 演示示例
  • 算法示例
  • 性能分析
  • 代码附录
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档