Floyd Warshall算法的时间复杂度

时间:2012-05-28 03:32:51

标签: algorithm graph shortest-path floyd-warshall

Skiena的算法书包含以下对Floyd Warshall algorithm的解释:

 floyd(adjacency_matrix *g)
 {
   int i,j; /* dimension counters */
   int k; /* intermediate vertex counter */
   int through_k; /* distance through vertex k */
   for (k=1; k<=g->nvertices; k++)
       for (i=1; i<=g->nvertices; i++)
           for (j=1; j<=g->nvertices; j++) {
                through_k = g->weight[i][k]+g->weight[k][j];
                if (through_k < g->weight[i][j])
                      g->weight[i][j] = through_k;
           }
  }
  

Floyd-Warshall全对最短路径在O(n 3 )时间内运行,这是渐近的   没有比n调用Dijkstra算法更好的了。但是,循环是如此   这个项目非常简短,以至于它在实践中运行得更好。值得注意的是   罕见的图算法在邻接矩阵上比邻接更好   列表。

有人可以详细说明为什么大胆的部分是真的吗?

3 个答案:

答案 0 :(得分:3)

  

但是,循环太紧,程序太短而无法运行   在实践中更好。

如果你看一下这个算法,就会有三个循环,只有两个语句嵌套在那些循环中。唯一的逻辑是在第三个嵌套循环中完成的。如果你运行了n Djikstra,那么逻辑将在第一个循环中完成,也可以在持续嵌套的情况下完成,这很容易让人觉得不干净。使用干净的三个循环,计算机也应该更容易管理内存。

答案 1 :(得分:2)

具有通用数据结构的Dijkstra算法是O(E log v),但Fibonacci堆将其改进为O(E + v log v),这是更复杂的数据结构,并且算法的常量工厂大于floyed。 查看此link中的运行时间。

这个问题的区别与q-sort和heap-sort

之间的差异相同

答案 2 :(得分:1)

让我们分解一下:

  

Floyd-Warshall全对最短路径在O(n 3 )时间内运行......

这是因为我们有一个三for个循环,每个循环都有 n 次迭代

  

...渐渐地没有比调用Dijkstra算法的n更好。 ...

回想一下,对Dijkstra算法的单次调用将告诉我们从一个特定节点 x1 到图中所有节点的所有最短路径。因此,我们可以对图中所有节点的Dijkstra算法进行 n 调用: x1 x2 ,... xn 找到从 x1 到所有节点的最短路径, x2 到所有节点,... xn 到所有节点。换句话说,这给了我们所有对最短路径 - 就像Floyd Warshall一样!

Running Dijkstra n times:
time = number of nodes × O((n + e)lgn)      [assuming binary heap used for Dijkstra]
     = n × O((n + e)lgn)                
     = O(n(n + e)lgn)

确实如此,Floyd-Warshall的 O(n ^ 3)时间并不优于 O(n(n + e)lgn)向Dijkstra发出 n 电话的时间。

  

...然而,循环太紧,程序太短,以至于在实践中运行得更好。

这里的关键词是“ in practice ”。请记住,渐近分析并不完美。它是性能的数学抽象/近似。当我们实际运行代码时,有许多实际因素没有考虑到。处理器具有复杂的低级架构,用于获取和运行指令。它pipelines说明,pre-fetches说明,尝试predict指令,caches指令和数据,......这是非常不可预测的!然而,所有这些低级优化都会对算法的整体性能产生巨大影响。理论上较慢的算法可以获得提升,理论上快速的算法可能无法获得相同的提升。这有时被称为大符号的hidden constant factor

事实证明,处理器喜欢优化嵌套的for循环和多维数组!这就是Skiena在这里提到的。数组的for循环充分利用了temporal and spacial locality,并且可以很好地处理低级处理器优化。另一方面,Dijkstra的算法也没有做到这一点,因此处理器优化也不起作用。因此,Dijkstra在实践中确实可能会变慢 Floyd-Warshall是一个“短程序”,意思是没有使用任何复杂的数据结构,重复的指令数量很少。这些事情以及处理器优化为Floyd-Warshall带来了一个隐藏的小因子。也就是说, O(k·n 3 中的 k 很小。