我用c ++实现了Floyd-Warshall的算法,用C ++编写了Coursera的MOOC。我使用std :: min来查找两个节点之间的当前距离和包含跳转的最小值(根据算法的标准伪代码)。 我发现与使用if条件相比,使用std :: min会增加程序的运行时间。
e.g。
if(a[i][j] > a[i][k]+a[k][j])
a[i][j] = a[i][k]+a[k][j];
而不是
a[i][j] = min (a[i][j], a[i][k] + a[k][j]);
我使用这些测试用例https://github.com/beaunus/stanford-algs/tree/master/testCases/course4/assignment1AllPairsShortestPath运行了这两个程序,并发现在较大的测试用例中,与带有if条件的代码相比,使用std :: min的代码需要两倍到三倍的时间。
[我知道已经提出了类似的问题,但这确实有任何真正的答案。] 编辑: 我标记了“HERE”,我用“std :: min”替换了if条件,性能差异很明显。 完整的代码在这里:
//This implements Floyd Warshall algorithm for all pairs- shortest paths.
#include<cstdio>
#include<algorithm>
const int INF=10000, NMAX=2048; //According to the constraints of the test-files.
using namespace std;
int A[NMAX+1][NMAX+1];
int main()
{
int n, m; //n= number of vertices, m = number of edges in the directed graph.
scanf("%d %d",&n,&m);
//Initializing array of distances.
for(int i=1; i<=n; i++)
{ for(int j=1; j<=n; j++)
{ A[i][j]=INF; //This makes distance from every node to every other node = INF.
}
A[i][i]=0; //distance from every node to itself is zero.
}
//Taking input of m edges and storing them.
int x, y, dist;
for(int i=0; i<m; i++)
{ scanf("%d %d %d",&x,&y,&dist);
if(A[x][y]>dist) // HERE.
A[x][y]=dist; // There is an edge with weight "dist", tail x and head y.
}
for(int k=1; k<=n; k++)
{ for(int i=1; i<=n; i++)
{ for(int j=1; j<=n; j++)
{ if(A[i][j] > A[i][k]+A[k][j]) //HERE.
A[i][j] = A[i][k]+A[k][j];
}
}
}
//This finds the minimum distance in shortest paths.
int mindist=0, mini, minj;
for(int i=1; i<=n; i++)
{ if(A[i][i]<0) //This happens iff there is negative cycle.
{ printf("NULL\n");
return 0;
}
for(int j=1; j<=n; j++) //Find the min shortest path distance between any pair of nodes.
{ if(mindist > A[i][j]) //HERE
{ mindist= A[i][j];
}
}
}
printf("%d\n",mindist);
return 0;
}
答案 0 :(得分:1)
这里的主要区别在于第二种形式,你(基本上)强制更新每个元素(虽然它可能是一个无变化的更新)。
在第一个版本中,您只需执行所需的更新。
这取决于您的体系结构,但如果数组较大且第二项较小的情况数相对较少,则可能导致不必要的内存写入。
调查问题的一种方法是使用条件运算符min
替换?:
。
如果是这种情况,性能将大致相同,因为开销不在min()
中,而是在不必要地将a[i][j]
的值写在自身上。
您也可以考虑创建对a[i][j]
的引用:
auto &v(a[i][j]);
为了帮助最小化索引计算(优化程序可能会为您执行此操作,但您不能伤害它)。
auto &v(a[i][j]);
if(v > a[i][k]+a[k][j]) {
v = a[i][k]+a[k][j];
}
注意:关于本地参考。任何合理的编译器都应该(通过优化)发现这个并发出相同的代码。但如果你不熟悉优化和学习,可能不是时候进入。手优化的常见缺点是可读性。我认为,优化版本无论如何都是可读的。