目录
1 弗洛伊德算法介绍
弗洛伊德算法(Floyd's algorithm),又称为全源最短路径算法,是一种用于解决图中所有节点之间最短路径的经典算法。
该算法的基本思想是通过动态规划的方式逐步更新路径长度,从而找到所有节点之间的最短路径。具体步骤如下:
-
创建一个二维数组
dis
,其中dis[i][j]
表示节点i到节点j的最短路径长度的估计值。初始时,dis[i][j]
的值为节点i到节点j的直接距离(如果两个节点之间有边相连),或者为无穷大(如果两个节点之间没有边相连)。 -
创建一个二维数组
pre
,其中pre[i][j]
表示节点i到节点j的最短路径上节点j的前一个节点的索引。初始时,pre[i][j]
的值为j(即节点j是节点i到节点j的最短路径上的前一个节点)。 -
对于每对节点i和j,以及所有中间节点k,检查是否存在一条经过节点k的路径,使得经过节点k的路径长度更短。如果存在这样的路径,则更新
dis[i][j]
和pre[i][j]
的值。- 如果
dis[i][j] > dis[i][k] + dis[k][j]
,则更新dis[i][j]
为dis[i][k] + dis[k][j]
,并更新pre[i][j]
为节点k的索引。
- 如果
-
重复第3步,对所有的节点i、j和k进行遍历,直到所有节点之间的最短路径长度都被计算出来。
-
最终,
dis
数组中的值即为所有节点之间的最短路径长度,pre
数组中的值可以用于回溯路径,从而得到最短路径的具体节点序列。
2 弗洛伊德算法中三大数组更新思路
在弗洛伊德算法中,有三个关键的数组需要更新:dis
数组、pre
数组和result
数组。
-
dis
数组的更新:在算法的初始化阶段,
dis
数组会被初始化为图中各个节点之间的直接距离。然后,在算法的迭代过程中,会逐步更新dis
数组中的值,以得到最短路径的长度。更新
dis
数组的过程是通过遍历中间节点k的方式进行的。对于每一对节点i和j,如果经过节点k的路径长度更短,则更新dis[i][j]
的值为dis[i][k] + dis[k][j]
。更新公式为:
dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j])
。 -
pre
数组的更新:pre
数组用于记录最短路径上每个节点的前一个节点的索引。在算法的迭代过程中,当更新dis[i][j]
的值时,也需要更新pre[i][j]
的值。更新
pre
数组的过程是通过将节点k作为中间节点时的情况进行判断。如果经过节点k的路径长度更短,则更新pre[i][j]
的值为节点k的索引。更新公式为:
pre[i][j] = pre[k][j]
。 -
result
数组的更新:result
数组用于存储最终的最短路径结果,即图中所有顶点对之间的最短路径。在算法的迭代过程中,每当更新
dis[i][j]
的值时,也需要更新result[i][j]
的值。根据路径的构建过程,可以根据pre
数组的值回溯路径,并将路径的节点顺序存储到result[i][j]
中。具体的路径构建过程在您提供的代码中已经进行了实现。
总的来说,弗洛伊德算法通过不断更新dis
数组和pre
数组的值,以及构建路径来寻找图中所有节点之间的最短路径。这些数组的更新是算法的核心步骤,通过动态规划的思想逐步更新路径长度和前一个节点的索引,从而得到最短路径的结果。
本篇主要讲解和实现更新路径的问题.
3 最短路径实现思路
弗洛伊德算法的时间复杂度为O(n^3),其中n是图中节点的数量。它适用于解决有向图或无向图中任意两个节点之间的最短路径问题。
-
首先,创建一个二维数组
result
,用于存储最终的结果,即图上所有顶点对之间的最短路径。 -
使用两个嵌套的for循环遍历二维数组
dis
,其中dis
是存储顶点之间距离的二维数组。 -
在每个循环中,获取当前顶点对应的起点和终点,并创建一个空的StringBuilder对象
path
用于构建路径。 -
对于特殊情况,当起点等于终点时,直接将终点添加到
path
中,表示路径只包含自身。 -
对于一般情况,通过查找
pre
数组来获取前一个顶点的索引。从终点开始,依次添加前一个顶点到path
中,直到前一个顶点等于起点。 -
由于路径是从终点到起点的顺序,因此需要将
path
进行反转,使其变为起点到终点的顺序。 -
对于
i > j
的情况,直接从result
数组中获取路径结果,并进行反转操作。 -
将构建好的路径字符串转换为String类型,并存储到
result
数组的对应位置。
4 核心代码实现
/**
* 根据前驱节点数组来创建一下结果数组,数组中存放能使图中所有节点对连通的距离最短的路径
*/
private void createResult() {
//打印最终的结果 也就是 打印出 图上所有顶点对儿的间相连的距离最短的那个路径
result = new String[vertexList.size()][vertexList.size()];
StringBuilder path = null;
for (int i = 0; i < dis.length; i++) {
for (int j = 0; j < dis.length; j++) {
String start = vertexList.get(i);
String end = vertexList.get(j);
path = new StringBuilder();
//如果是自己 也就是 i==j时 直接打印start(或end)即可
if (i == j) {
path.append(end);
} else if (i < j) {
int preIndex = pre[i][j];
path.append(end);
while (preIndex != i) {
path.append("-").append(vertexList.get(preIndex));
preIndex = pre[i][preIndex];
}
path.append("-").append(start);
path.reverse();
} else {
path = new StringBuilder(result[j][i]).reverse();
}
result[i][j] = String.valueOf(path);
}
}
}
5 调用并输出路径结果
//根据上面的createResult方法来打印输出一下路径结果
public void showResult() {
//先把结果给我创建好了
createResult();
System.out.println("\n所有顶点对之间的最短路径如下:");
for (int i = 0; i < result.length; i++) {
for (int j = 0; j < result.length; j++) {
String start = vertexList.get(i);
String end = vertexList.get(j);
System.out.printf(" %s - %s: %-8s", start, end, result[i][j]);
}
System.out.println();
}
}
6 结果展示
7 总结
总体而言,以上代码实现了弗洛伊德算法中创建最短路径数组的逻辑。它正确地根据dis
数组和pre
数组构建了最短路径,并将结果存储在result
数组中。然而,为了确保代码的正确性,建议在实际使用前进行测试和验证,尤其是对于pre
数组的更新和路径的起点和终点的顺序进行仔细检查。