我已经读到使用 ofstrlen
比这样的测试更昂贵:
我们有一个x
100 个字符长的字符串。
我觉得
for (int i = 0; i < strlen(x); i++)
比这段代码贵:
for (int i = 0; x[i] != '\0'; i++)
这是真的吗?也许第二个代码在某些情况下不起作用,那么使用第一个更好吗?
下面的会更好吗?
for (char *tempptr = x; *tempptr != '\0'; tempptr++)
我已经读到使用 ofstrlen
比这样的测试更昂贵:
我们有一个x
100 个字符长的字符串。
我觉得
for (int i = 0; i < strlen(x); i++)
比这段代码贵:
for (int i = 0; x[i] != '\0'; i++)
这是真的吗?也许第二个代码在某些情况下不起作用,那么使用第一个更好吗?
下面的会更好吗?
for (char *tempptr = x; *tempptr != '\0'; tempptr++)
for (int i=0;i<strlen(x);i++)
此代码正在调用strlen(x)
每次迭代。所以如果x
长度为 100,strlen(x)
将被调用 100 次。这是非常昂贵的。此外,每次都以与 for 循环相同的方式进行strlen(x)
迭代。x
这使其复杂度为 O(n^2)。
for (int i=0;x[i]!='\0';i++)
此代码不调用任何函数,因此将比前面的示例快得多。由于它只遍历循环一次,因此复杂度为 O(n)。
第一个代码在 i 的每次迭代中检查 x 的长度,找到最后一个 0 需要 O(n),所以需要 O(n^2),第二种情况是 O(n)
是的,您的第二个可能无法 100% 工作,但它会稍微完全正常。这是因为在使用 strlen() 时,您必须每次都调用该方法。更好的方法是这样
int strLength = strlen(x);
for (int i = 0; i < strLength; i++)
希望这可以帮助。
我可以假设在第一个变体中,您会在每次迭代中找到 strlen,而在第二个变体中,您不会这样做。
试试这个来检查:
int a = strlen(x);
for (int i = 0; i < a; i++) {...}
我猜编译器可以优化(检查 Gregory Pakosz 评论)你的第一个 for 循环,这样你就会像这样:
int len = strlen(x);
for (int i = 0; i < len; i++)
这仍然是O(n)
。
无论如何,我认为你的第二个for
循环会更快。
如果没有,则没有编译优化。是的,因为 strlen 每次都会迭代字符串的每个字节,而第二个实现只会执行一次。
值得注意的是,如果您不针对包含字符串的缓冲区大小测试索引,您可能会面临缓冲区溢出问题。根据您使用此代码所做的工作,这可能是一个实际问题,也可能不是,但进行额外检查很少会造成伤害,这是一个养成的好习惯。
我建议: for (i = 0; i < buf_size && x[i] != '\0'; i++)
在哪里:
buf_size
是缓冲区的预定大小。如果x
是一个数组,这将是sizeof(x)
; ifx
是一个指针,你应该有可用的缓冲区大小。i
从循环中删除了声明,因为它只是有效的 c99。如果您只在 c99 下编译,请随时将其放回原处。当然,第一个比第二个需要更长的时间。他们实际上根本不做同样的事情——第一个是每次都计算字符串的长度;第二个是(有效地)只做一次。
第一个版本等价于:
for (int i=0; x[i] != 0; i++)
for (int j=0; j<i; j++)
;
也许您的意思是“调用库 strlen() 比实现我自己的库更有效吗?” 答案当然是“视情况而定”。您的编译器可能具有 strlen() 的内在版本,这些版本的优化超出了您对源代码的期望,您可能位于函数调用昂贵的平台上(现在很少见),等等。
唯一既通用又正确的答案是“分析并找出答案”。