推出一个新系列,《看图轻松理解数据结构和算法》,主要使用图片来描述常见的数据结构和算法,轻松阅读并理解掌握。本系列包括各类堆、各类队列、各类列表、各类树、各类图、各类排序等等几十篇的样子。mysql
Floyd是一种经典的多源最短路径算法,它经过动态规划的思想来寻找给定加权图中的多源点之间的最短路径,算法时间复杂度是O(n3)。之因此叫Floyd是由于该算法发明人之一是Robert Floyd,他是1978年图灵奖得到者,同时也是斯坦福大学计算机科学系教授。算法
对于n个点的加权图,从加权图的权值矩阵开始,递归地更新n次最终求得每两点之间的最短路径矩阵。即加权图的邻接矩阵为,按必定公式对该矩阵进行递归更新,初始时矩阵为D(0),第一次,根据公式用D(0)构建出矩阵D(1);第二次,根据公式用D(1)构建出矩阵D(2);以此类推,根据公式用D(n-1)构造出矩阵D(n),D(n)即为图的距离矩阵,i行j列表示顶点i到顶点j的最短距离。sql
如何理解这种动态规划算法呢?能够理解为逐一选择中转点,而后针对该中转点,全部以此为中转点的其它点都要根据规定进行更新,这个规定就是原来两点之间的距离若是经过该中转点变小了则更新距离矩阵。好比选择“1”做为中转点,原来“02”之间的距离为5,经过中转点1后(即路径变为“012”)距离为4,变小了,那么就更新距离矩阵对应的元素,由5更新为4。当图中全部顶点都被做为中转点处理之后,那么获得的最后距离矩阵就是多源最短距离矩阵了。数组
设为i到j的中间节点编号不超过k的最短距离,当k=0时,
,对于n个顶点的图,咱们要求的i到j的最短距离便是
。bash
如今咱们创建和
之间的递归关系,对于任意k,
,因而能够根据该递归关系获得最终的最短路径,即中间节点编号不超过n-1的最短距离。网络
Floyd算法核心就是下列五行代码,能够体会一下,三个for循环嵌套,最外层的k便是循环取不一样中转点时的状况,分别让图中每一个顶点做为中转点去更新距离,完成全部循环后就是最终的最短距离矩阵。数据结构
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(d[i][k]+d[k][j]<d[i][j])
d[i][j]=d[i][k]+d[k][j];
复制代码
优势:容易理解,能够算出任意两个节点之间的最短距离,代码编写简单。对于稠密图效果最佳,边权可正可负。并发
缺点:时间复杂度比较高,不适合计算大量数据。机器学习
对于一个拥有7个顶点的无向加权图,分别用0-6来表示图的每一个顶点,每条边上的数字为对应的权重。数据结构和算法
首先根据每条边的权重来初始化距离矩阵,这是一个[7x7]的矩阵,行列分别对应两个顶点,好比第0行第1列表示顶点0到顶点1,对应的值为3,即权值为3。以此类推,其它元素分别表明对应边的权重。
逐一查找看是否有以0为中转点使得距离更短,实际上并不用比较全部矩阵的元素,只需比较知足if (i != j && j != k && i != k)
条件的元素,即都为0的对角线和中转点对应的行列不用比较,由于对角线上的元素表示顶点本身到本身的距离,因此无需比较,而中转点对应的行列表示顶点到中转点的距离,也无需比较。
比较d[1][2]
与d[1][0]+d[0][2]
,由于1<3+5,因此不更新d[1][2]
。
往下,比较d[1][3]
与d[1][0]+d[0][3]
,由于4<3+INF,因此不更新d[1][3]
。
往下,比较d[1][4]
与d[1][0]+d[0][4]
,由于INF<3+INF,因此不更新d[1][4]
。接着往下d[1][5]
、d[1][6]
两个元素状况相似。
比较d[2][1]
与d[2][0]+d[0][1]
,由于1<3+5,因此不更新d[2][1]
。
往下,比较d[2][3]
与d[2][0]+d[0][3]
,由于4<5+INF,因此不更新d[2][3]
。
往下,比较d[2][4]
与d[2][0]+d[0][4]
,由于8<5+INF,因此不更新d[2][4]
。
往下,比较d[2][5]
与d[2][0]+d[0][5]
,由于2<5+INF,因此不更新d[2][5]
。
往下,比较d[2][6]
与d[2][0]+d[0][6]
,由于INF<5+INF,因此不更新d[2][6]
。
比较d[3][1]
与d[3][0]+d[0][1]
,由于4<INF+3,因此不更新d[3][1]
。
相似地,剩下的元素所有都不更新,最后比较完d[6][5]
与d[6][0]+d[0][5]
后即完成了以0做为中转点的所有比较工做。
逐一查找看是否有以1为中转点使得距离更短,比较d[0][2]
与d[0][1]+d[1][2]
,
由于5>3+1,因此将d[0][2]
的值更新为4。
比较d[0][3]
与d[0][1]+d[1][3]
,
由于INF>3+4,因此将d[0][3]
的值更新为7。
第0行接着的三个元素都不更新,到第2行后,比较d[2][0]
与d[2][1]+d[1][0]
,
由于5>1+3,因此将d[2][0]
的值更新为4。第二行剩余的元素都无需更新。
开始第3行,比较d[3][0]
与d[3][1]+d[1][0]
,
由于INF>4+3,因此将d[3][0]
的值更新为7。
接着以顶点1做为中转点时剩余的所有元素都无需更新。
逐一查找看是否有以2为中转点使得距离更短,比较d[0][1]
与d[0][2]+d[2][1]
,由于3<4+1,因此d[0][1]
不更新。
比较d[0][3]
与d[0][2]+d[2][3]
,由于7<4+4,因此d[0][3]
不更新。
比较d[0][4]
与d[0][2]+d[2][4]
,
由于INF>4+8,因此将d[0][4]
的值更新为12。
相似地,对以顶点2做为中转点的所有剩余元素进行比较更新。
逐一查找看是否有以3为中转点使得距离更短,比较d[0][1]
与d[0][3]+d[3][1]
,由于3<7+4,因此d[0][1]
不更新。
比较d[0][2]
与d[0][3]+d[3][2]
,由于4<7+4,因此d[0][2]
不更新。
相似地,对以顶点3做为中转点的所有剩余元素进行比较更新。
逐一查找看是否有以4为中转点使得距离更短,比较d[0][1]
与d[0][4]+d[4][1]
,由于3<12+9,因此d[0][1]
不更新。
比较d[0][2]
与d[0][4]+d[4][2]
,由于4<12+8,因此d[0][2]
不更新。
相似地,对以顶点4做为中转点的所有剩余元素进行比较更新。
逐一查找看是否有以5为中转点使得距离更短,比较d[0][1]
与d[0][5]+d[5][1]
,由于3<6+3,因此d[0][1]
不更新。
比较d[0][2]
与d[0][5]+d[5][2]
,由于4<6+2,因此d[0][2]
不更新。
相似地,对以顶点5做为中转点的所有剩余元素进行比较更新。
逐一查找看是否有以6为中转点使得距离更短,比较d[0][1]
与d[0][6]+d[6][1]
,由于3<9+6,因此d[0][1]
不更新。
比较d[0][2]
与d[0][6]+d[56][2]
,由于4<9+5,因此d[0][2]
不更新。
相似地,对以顶点6做为中转点的所有剩余元素进行比较更新。
将全部顶点做为中转点处理后,最终获得了一个矩阵,这个矩阵就是图的每一个顶点两两最短距离矩阵。好比a[0][4]=12
就是顶点0到顶点4的最短距离为12。同时能够看到距离矩阵是以对角线为轴对称的。
-------------推荐阅读------------
个人开源项目汇总(机器&深度学习、NLP、网络IO、AIML、mysql协议、chatbot)
跟我交流,向我提问:
欢迎关注: