【发布时间】:2020-05-16 16:42:26
【问题描述】:
我有一个新手问题。
假设我有以下简单的嵌套循环,其中m 和n 不一定相同,但确实是大数字:
x = 0;
for (i=0; i<m; i++)
{
for (j=0; j<n; j++)
{
delta = CalculateDelta(i,j);
x = x + j + i + delta;
}
}
现在我有了这个:
x = 0;
for (i=0; i<m; i++)
{
for (j=0; j<n; j++)
{
delta = CalculateDelta(i,j);
x = x + j + i + delta;
j++;
delta = CalculateDelta(i,j);
x = x + j + i + delta;
}
}
规则:我确实需要遍历循环的所有元素,因为这个 delta 计算。
我的问题是:
1) 第二种算法比第一种算法快,还是一样? 我有这个疑问,因为对我来说,第一个算法的复杂度为 O(m * n),而第二个算法的复杂度为 O(m * n/2)。还是不需要较低的复杂性使其更快?
2) 如果没有Parallel. For 之类的东西,还有其他方法可以加快速度吗?
3) 如果我使用Parallel. For,它真的会更快吗,因为我可能需要对x 变量进行同步锁定?
谢谢!
【问题讨论】:
-
当然可以并行化。 x 可以计算为 i 和 j 以及所有增量之和的函数。可以与典型的“收集”模式并行执行求和。 (假设 CalculateDelta 是一个纯函数 - 仅取决于它的参数并且没有副作用。)而且,不,展开可能对您几乎没有任何作用。事实上,当 n 为奇数时,您的做法只会导致错误。
-
您并没有降低复杂性。它仍然与 n 成正比。即使您在循环中展开一百万次迭代。它访问循环的次数仍然与 n 成正比,因此复杂度没有改变。
-
第二个与第一个不同,因为它可能会为等于
n的j值计算增量。基本上,如果n是一个奇数,比如 3,那么第一个循环执行 j=0 和 j=1,然后下一个循环执行 j=2 和 j=3,因为第一个循环会在 j=2 处停止,您可以“修复”在j++之后有一个if(j>=n) break;但这仍然是n操作。
标签: c# .net time-complexity computation-theory code-complexity