我最近注意到我的一位同事正在做
int len = foo.length();
for (int i = 0; i < len; ++i)
doStuff(foo[i]);
我知道这在C中被认为是一种很好的做法,其中strlen()在O(length_of_string)中运行。但是我希望更新的语言(比如Java或Python)能够将字符串的长度与字符一起存储,从而允许length()在O(1)中运行。我经常写:
for (int i = 0; i < foo.length(); ++i)
doStuff(foo[i]);
保存一行代码。但我的同事让我感到疑惑......这是非常好的做法,还是期望O(1)行为是不合理的?
(作为相关问题:现代编译器现在不能自动从for-header中提取strlen()调用吗?)
答案 0 :(得分:1)
这些陈述实际上是两种不同的陈述。
int len = foo.length(); // Will run once
for (int i = 0; i<len;++i)
这里将检查i<len
每个循环,len只是一个可以读取的变量。
for (int i = 0; i < foo.length(); ++i)
此处i < foo.length()
包含函数调用,因为foo
的长度可以在循环内部发生变化(例如,您可以删除foo
之外的字符而不是递增i
})每次迭代都会调用函数foo.length()
。
有些语言中foo可能是常量,foo.length()可以由编译器优化,但最好是保存而不是遗憾。
此外,某些语言可能允许这样的内容:
for (int i=0, len=foo.length();i<len;++i)
仍然可以为你节省一条线。
答案 1 :(得分:0)
首先,调用函数foo.length()在任何情况下,循环的每次迭代都需要比使用临时变量来存储调用foo.length()的结果更多的资源。
此外,在重构代码时,使用代码可能会导致错误。例如,这个循环永远不会结束:
for (int i = 0; i < foo.length(); ++i)
{
doStuff(foo[i]);
// few line of code, written another man
doWork(foo); // Passing by reference
}
void doWork(Foo fooObj)
{
// some work
fooObj.Add(new SomeObject());
}
答案 2 :(得分:0)
这不是语言不可知的。这取决于编译器的智能程度。如果您可以明确声明长度是常量,则可以内联整个循环,因此根本不会发生任何测试。谈到Java,我敢打赌编译器可以变得非常聪明,所以你不必那么明确。你正确的java.lang.String预先计算它的长度。在复杂性方面,定义您正在计算的重要操作是切实可行的。严格来说,在图灵机上你必须是O(n)才能找到输入的结尾(“$”)。