C数据结构与算法-基础整理-图-08:详解弗洛伊德算法

详解最短路径中的弗洛伊德算法

0x01.关于弗洛伊德算法

Floyd算法又称为插点法,是一种利用动态规划的思想寻找给定的加权图中多源点之间最短路径的算法,与Dijkstra算法类似。该算法名称以创始人之一、1978年图灵奖获得者、斯坦福大学计算机科学系教授罗伯特·弗洛伊德命名。 

0x02.算法代码

void ShortestPath_Floyd(Graph G, int** P, int** D)
{
	int v, w, k;
	for (v = 0; v < G.numv; v++)
	{
		for (w = 0; w < G.numv; w++)
		{
			D[v][w] = G.edge[v][w];//初始化D数组为邻接矩阵
			P[v][w] = w;//初始化P数组
		}
	}
	for (k = 0; k < G.numv;k++)
	{
		for (v = 0; v < G.numv; v++)
		{
			for(w=0;w<G.numv;w++)
			{
				if (D[v][w] > D[v][k] + D[k][w])//如果经过k中转的路径比直接相连更短,则替换
				{
					D[v][w] = D[v][k] + D[k][w];
					P[v][w] = P[v][k];
				}
			}
		}
	}
	for (v = 0; v < G.numv; v++)//打印任意两个顶点间的路径
	{
		for (w = v + 1; w < G.numv; w++)
		{
			printf("%c-%c weight:%d\n", G.ver[v], G.ver[w], D[v][w]);
			k = P[v][w];
			printf("Path :%c", G.ver[v]);
			while (k != w)
			{
				printf(" ->%c", G.ver[k]);
				k = P[k][w];
			}
			printf(" ->%c", G.ver[w]);
		}
		printf("\n");
	}
}

0x03.原理详解

弗洛伊德算法不关代码简洁不少,而且很容易理解,不需要逐一分析运行过程就可以理解。

二维数组D存储的是任意两个顶点间最短路径,比如D[2][8]存储的就是顶点V2到顶点V8的最短路径,初始化为邻接矩阵是为了更多的记录与邻接边有关的权值大小,在三层嵌套循环中,每一次最内层的循环都是比较D[v][w]与D[v][k]+D[k][w]的大小,这个原理是如果v,w相邻,那么D[v][w]记录的是当前两个顶点间的之间的直接距离,也就是矩阵中的权值大小,如果不是最短,那么替换,因为是从内到外展开循环的,所以之后的计算都用到了之前计算好的数据,如果v,w不相邻,那么值应该是INTMAX,那么还是与转接到k的路径比较,因为对两个点来说,最短路径除了直接相连就是转接到第三个点k,这个算法巧妙的利用了这一点。

二维数组P存储的是任意顶点的路径中的前驱顶点,例如,P[0][8]表示V0到V8所需经历的第一个结点,依次类推,只要反复的用到k=P[k][w],就能求出最终路径,这个与上个算法相似,不同的是一维和二维的差距。

这个算法的时间复杂度是O(n^{3}),但是直接得出了整个图的最短路径,任意两个顶点之间的路径。

0x04.弗洛伊德算法和迪杰斯特拉算法比较

相比而言,弗洛伊德算法更适合从指定顶点而言的最短路径求法,如果需要用到大量的最短路径,最好使用弗洛伊德算法。

本章结束。

发布了50 篇原创文章 · 获赞 35 · 访问量 1317

猜你喜欢

转载自blog.csdn.net/ATFWUS/article/details/104389057
今日推荐