我正在使用c ++,c#和java实现Floyd-Warshall算法。在每种语言中,我在测试结果后使用顺序和并行实现:
(经过的时间仅适用于主要功能和阅读文件,Inti of Variable和...均未测量。)
在此处下载资源SourceCodes
OpenMp
进行Prallel 如果
NumOfThreads
= 1则为顺序,否则为并行
变量
#define n 1000 /* Then number of nodes */
double dist[n][n];
void floyd_warshall(int NumOfThreads) {
int i, j, k;
omp_set_num_threads(NumOfThreads);
for (k = 0; k < n; ++k)
#pragma omp parallel for private(i,j)
for (i = 0; i < n; ++i)
for (j = 0; j < n; ++j)
if ((dist[i][k] * dist[k][j] != 0) && (i != j))
if ((dist[i][k] + dist[k][j] < dist[i][j]) || (dist[i][j] == 0))
dist[i][j] = dist[i][k] + dist[k][j]; }
java变量
public final int numNodes =1000;
public final double[][] costs= new double[numNodes][numNodes] ;
我没有把java代码放在这里,因为它的工作正常(我认为)
可变
const int n = 1000;
static double[,] dist = new double[n, n];
并行代码
static void floyd_warshall(ParallelOptions pOp)
{
int k;
for (k = 0; k < n; ++k)
Parallel.For<int>(0, n, pOp, () => 0, (i, loop, j) =>
{
for (j = 0; j < n; ++j)
if ((dist[i, k] * dist[k, j] != 0) && (i != j))
if ((dist[i, k] + dist[k, j] < dist[i, j]) || (dist[i, j] == 0))
dist[i, j] = dist[i, k] + dist[k, j];
return 0;
}, (j) => { });
单一代码
static void floyd_warshallSingle()
{
int i, j, k;
for (k = 0; k < n; ++k)
for (i = 0; i < n; ++i)
for (j = 0; j < n; ++j)
if ((dist[i,k] * dist[k,j] != 0) && (i != j))
if ((dist[i,k] + dist[k,j] < dist[i,j]) || (dist[i,j] == 0))
dist[i,j] = dist[i,k] + dist[k,j];
}
我的c#实施有什么问题?
全部使用相同的文件
现在我的问题是为什么用c#解决这个算法需要更多的时间?
java和c ++的运行时间几乎相同,但我认为我用c#实现是错误的,因为c#和c ++之间的区别很奇怪!
请帮我改进我的C#实现或命名一些原因谢谢!
编辑1
我将数组更改为锯齿状数组,结果更改为:
仍然是c#和c ++或java之间的巨大差异!知道为什么吗? 新变量
const int n = 1000;
static double[][] dist = new double[n][];
新代码:
static void floyd_warshallSingle()
{
int i, j, k;
for (k = 0; k < n; ++k)
for (i = 0; i < n; ++i)
for (j = 0; j < n; ++j)
if ((dist[i][k] * dist[k][j] != 0) && (i != j))
if ((dist[i][k] + dist[k][j] < dist[i][j]) || (dist[i][j] == 0))
dist[i][j] = dist[i][k] + dist[k][j];
}
static void floyd_warshall(ParallelOptions pOp)
{
int k;
for (k = 0; k < n; ++k)
Parallel.For<int>(0, n, pOp, () => 0, (i, loop, j) =>
{
for (j = 0; j < n; ++j)
if ((dist[i][k] * dist[k][j] != 0) && (i != j))
if ((dist[i][ k] + dist[k][j] < dist[i][ j]) || (dist[i][j] == 0))
dist[i][ j] = dist[i][k] + dist[k][j];
return 0;
}, (j) => { });
}
答案 0 :(得分:2)
确定它的数组边界检查或至少确定数组边界检查是否是问题的部分的一种方法是删除一些索引计算。例如:
static void floyd_warshallSingle()
{
int i, j, k;
for (k = 0; k < n; ++k)
{
var distk = dist[k];
for (i = 0; i < n; ++i)
{
var disti = dist[i];
for (j = 0; j < n; ++j)
if ((i != j) && (disti[k] * distk[j] != 0))
if ((disti[j] == 0) || disti[k] + distk[j] < disti[j])
disti[j] = disti[k] + distk[j];
}
}
}
我所做的就是使用distk
作为对dist[k]
的引用。我怀疑编译器已经在进行优化,这很可能是你从矩形阵列变为锯齿状阵列时所获得的性能提升。但值得一试。
另外,你说你在没有连接调试器的情况下运行。我假设您还在运行发布版本?所有三个程序(C ++,Java和C#)都运行相同的位数吗?也就是说,它们都是64位可执行文件吗?所有32位可执行文件?小心C#,因为&#34;首选32位&#34;可以在项目选项中打开标志。当您使用&#34;任何CPU&#34;进行编译时,即使在64位系统上,也可能导致您以32位模式运行。