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