有没有一种更有效的方法可以省略for循环实例
本文关键字:for 实例 循环 方法 一种 有效 有没有 | 更新日期: 2023-09-27 18:29:37
如果我有一个标准的for循环,有没有更有效的方法可以省略某些出现?
例如:
A:
for (int i = 0; i < n; i++)
{
if (i != n / 2 && i != n / 3 && i != n / 4)
{
val += DoWork(i);
}
else
{
continue;
}
}
B:
for (int i = 0; i < n / 4; i++)
{
val += DoWork(i); ;
}
for (int i = n / 4 + 1; i < n / 3; i++)
{
val += DoWork(i);
}
for (int i = n / 3 + 1; i < n / 2; i++)
{
val += DoWork(i);
}
for (int i = n / 2 + 1; i < n; i++)
{
val += DoWork(i);
}
C:
for (int i = 0; i < n; i++)
{
if (i == n / 2 || i == n / 3 || i == n / 4)
{
continue;
}
else
{
val += DoWork(i);
}
}
对于n = int.MaxValue
,结果如下:A结果:57498毫秒。B结果:42204毫秒。C结果:57643毫秒。
根据@Churk的回答进行编辑。我添加了另一个测试用例方法D如下:
D:
for (int i = 0; i < n; i = (i != n / 2 -1 && i != n / 3 -1 && i != n / 4-1) ? i+1: i+2)
{
val += DoWork(i);
}
得到以下结果:
A结果:56355毫秒。B结果:40612毫秒。C结果:56214毫秒。D结果:51810毫秒。
第2版:在预先计算循环外n/2 n/3和n/4的值后得到:
A结果:50873毫秒。B结果:39514毫秒。C结果:51167毫秒。D结果:42808毫秒。
D循环似乎再次接近B的"展开",A和C仍然需要更多的时间。
就每种方法之间的比较而言,这些都是我所期望的。
我的问题是,有没有更有效的方法来做到这一点?
这在一定程度上取决于上下文。在许多情况下,一种可能性是作弊。因此,与其省略数字,不如将它们包括在内,然后从你不想要的数字中反转结果:
for (int i = 0; i < n; i++)
{
val += DoWork(i);
}
val -= DoWork(i/2);
val -= DoWork(i/3);
val -= DoWork(i/4);
根据DoWork操作的成本,您从比较中节省的时间可能会超过两次计算某些数字的结果。
为循环嵌入次要条件
未测试:
for (int i = 0; i < n || (i != n / 2 && i != n / 3 && i != n / 4); i++)
val += DoWork(i);
}
我认为只要其中一个条件成立,它就会继续
首先,只需在40-60秒内暂停几次,就可以大致了解DoWork
中的时间比例。如果你甚至可以让你的循环花一点时间,你仍然需要花掉这部分时间。
现在看看你们的比较。每个人都在问一个问题。如果一个问题的答案几乎总是正确或几乎总是错误,那么这就是一个加速的机会。(所有的log(n)和n*log(n)算法都是通过使它们的决策点更像公平硬币来工作的。)
所以你可以看到为什么你的B更快。平均而言,它在每个循环中提出的问题更少。通过展开循环(提问次数更少),你可以让它变得更快。
(我知道,我知道,编译器可以展开循环。嗯,也许。自己做吧,你不必在上面下注。)
您可以计算循环外的值,然后跳过它们:
int skip1 = n/2;
int skip2 = n/3;
int skip3 = n/4;
for (int i = 0; i < n; i++)
{
if (i != skip1 && i != skip2 && i != skip3)
{
val += DoWork(i);
}
}
不过,不确定这是否能节省足够的毫秒。
更新:我刚刚注意到@surfen在评论中建议了这一点。
如果DoWork()
不是瓶颈,那么它是一个足够小的方法,可以嵌入到循环中,因此您不需要单独花费时间的调用。如果DoWork()
完成了大部分工作,那么您就是在浪费时间:)
您可以计数操作。。。
选项A:n
在for循环中检查i
,然后对每个不是该值的i进行3次检查。。。所以只有4n个操作用于检查。
选项B:
您只是在间隔中循环,所以您正在执行n-3
操作。
选项C:
与选项A相同,4n
操作。
我不会麻烦用这样的修改来复杂化代码(因为很多人已经对你的问题发表了评论)
相反,您可能希望使用Pararell.ForEach在多个线程中同时运行DoWork。如果您的DoWork()做任何事情,这将对性能产生更大的影响。