在编写一个for
开始和结束条件都知道的循环时,哪种方式更好?假设我必须迭代一个循环以添加大小为 5 的数组元素。在这种情况下,就执行时间而言,以下哪一项会更有效?哪一个会提供更好的性能?
for (i = 0; i < 5; i++)
{
/* logic */
}
或者
for (i = 4; i >= 0; i--)
{
/* logic */
}
除了写作难i = 5 - 1;
,i = 4;
还有其他考虑吗?
通常建议集中精力使代码尽可能清晰和合乎逻辑,而不用担心微优化或其他因素。在您的情况下,第一个是更好的选择,因为大多数程序员更习惯于按该顺序遍历数组。
两个版本将具有相同的结果(假设它们已正确实现)并且将具有完全相同的运行时间。
编辑:@Zane 在评论中提到,前段时间向后循环到零更快。之所以如此,是因为将变量与零进行比较更快。鉴于当时计算机的速度要慢得多,因此鼓励进行此类优化。那些日子真的结束了……
你的代码有问题。第一个循环很好,但第二个 while 永远不会执行:它运行了 0 次。它应该是
for(i=4;i>=0;i--){}
此外,如果您问哪个更好,这是您的选择,您喜欢哪个。对我来说,我觉得第一个更舒服。
在大多数情况下,这无关紧要,但是在某些情况下,不明显的副作用可能会干扰。考虑一个循环:
for(int i = 0; i < strlen(str); i++) {/* do stuff on i-th elem */}
. 在每次迭代中,都会重新评估 strlen(str)(除非经过编译器优化),即使它完全没有必要;程序员很可能甚至没有考虑到这一点。可能值得将循环替换为:
for(int i = strlen(str); i > 0; i--) {/* do stuff on i-th elem */}
. 这里字符串的长度只会被评估一次。
当然,在第一个循环中,也可以通过使用附加变量来保存字符串的长度来避免该问题,但这只是不必要的噪音,与程序逻辑无关。
最明显的答案是:哪一个有你想要的语义?他们以不同的顺序访问对象。
作为一般规则,如果没有其他考虑,人们期望升序,这就是您在访问对象时应该使用的。在 C++ 中,为此使用迭代器更为惯用。普通迭代器按升序访问,反向迭代器按降序访问。如果您不明确需要降序,则应使用普通迭代器。这是人们所期望的,当你使用反向迭代器时,读者首先会问为什么。此外,我还没有测量,但如果普通迭代器比反向迭代器更快,我不会感到惊讶。在 Java 中,迭代器也是惯用的,并且没有反向迭代器。
如果我在访问时确实需要降序,我将使用 while 循环(如果我没有反向迭代器,它会为我做);我发现类似:
int index = numberOfElements;
while ( index != 0 ) {
-- index;
// ...
}
比任何替代方案都更具可读性(并且更容易正确)。
如果您不访问对象,而只是计数,那么降序对我来说似乎更自然:控制变量包含剩余的次数。而且由于计数从不用作索引,因此将它作为索引是一次性的这一事实没有问题,您可以使用传统的for
.
for ( int count = numberOfTimes; count != 0; -- count ) {
// ...
}
但这确实是风格问题。我也看到了很多上升循环。
我相信大多数程序员可以使用第一种方法(i++)更快地理解你的代码。除非您需要反向处理数组,否则我会坚持使用您的第一种方法。至于性能,我相信这两种解决方案都没有什么好处。
此外,您可能需要考虑使用 for..each (增强的 for)语法,该语法相当整洁。
int[] x = {1,2,3,4,5};
for(int y: x){
System.out.println(y);
}
我想说 i++ 的循环更容易理解。此外,后退可能会使处理器缓存的使用欠佳,但通常编译器/虚拟机比这更智能。
增量 for 循环或减量 for 循环是根据您希望使用 counter 变量的方式或它的外观来选择的
如果您按升序访问某个数组,则将使用递减的 for 循环
for (i = 0; i < 5; i++)
{
arr[i];
}
如果您按降序访问某个数组或列表,则使用增量 for 循环
for (i = 5; i > 0 ; i--)
{
arr[i-1];
}
如果计数器编号对访问的值没有意义,则查看代码的可读性。并且增量 for 循环看起来更令人赏心悦目。