如果我有一个标准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
,结果如下:
结果: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);
}
并得到以下结果:
结果:56355毫秒。 B结果:40612毫秒。 C结果:56214毫秒。 D结果:51810毫秒。
Edit2:预先计算出n / 2 n / 3和n / 4之外的值得到了:
结果:50873毫秒。 B结果:39514毫秒。 C结果:51167毫秒。 D结果:42808毫秒。
D循环似乎再次接近B的“展开”,A和C仍然花费更多的时间。
就每种方法之间的比较而言,这与我的预期有关。
我的问题是,有更有效的方法吗?
答案 0 :(得分:3)
这取决于上下文。在许多情况下,一种可能是作弊。因此,不要省略数字,只需包含它们,然后将结果从您不想要的数字反转:
for (int i = 0; i < n; i++)
{
val += DoWork(i);
}
val -= DoWork(i/2);
val -= DoWork(i/3);
val -= DoWork(i/4);
从比较中节省的时间可能会超过计算两次数字的结果,具体取决于DoWork操作的成本。
答案 1 :(得分:2)
将您的次要条件嵌入循环
未测试:
for (int i = 0; i < n || (i != n / 2 && i != n / 3 && i != n / 4); i++)
val += DoWork(i);
}
我认为只要其中一个条件成立,它就能继续运行
答案 2 :(得分:1)
首先,在40-60秒内暂停几次,这样你就可以清楚地知道DoWork
中有多少时间。如果你甚至可以让你的循环没有时间,你仍然需要花费那部分。
现在看看你的比较。 每个人都在问一个问题。 如果问题的答案几乎总是真或几乎总是假,那么这是一个获得加速的机会。 (所有log(n)和n * log(n)算法的工作原理是使他们的决策点更像是公平的硬币。)
所以你可以看到为什么你的B更快。平均而言,每个循环要求的问题更少。 通过展开循环(更频繁地询问问题),你可以更快地完成它。
(我知道,我知道,编译器可以展开循环。好吧,也许。自己做吧,你不必赌它。)
答案 3 :(得分:0)
您可以计算循环外的值,然后跳过它们:
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在评论中提出了这个建议。
答案 4 :(得分:-1)
如果DoWork()
不是瓶颈,那么这是一个足够小的方法可以嵌入到循环中,因此您不需要自行花费时间的调用。如果DoWork()
完成了大部分工作,那么你就是浪费时间的人:)
答案 5 :(得分:-1)
你可以计算操作......
选项A:
n
检查for循环中的i
,然后检查每个不是该值的i ...所以只有4n个操作用于检查。
选项B:
您只需循环显示间隔,因此您正在进行n-3
操作。
选项C:
与选项A,4n
操作相同。
答案 6 :(得分:-1)
我不会因为这些修改而使代码复杂化(因为很多人已经对你的问题发表了评论)
相反,您可能希望使用Pararell.ForEach在多个线程中同时运行DoWork。如果您的DoWork()做任何事情,这将对性能产生更大的影响。