21

我已经读到使用 ofstrlen比这样的测试更昂贵:

我们有一个x100 个字符长的字符串。

我觉得

for (int i = 0; i < strlen(x); i++)

比这段代码贵:

for (int i = 0; x[i] != '\0'; i++)

这是真的吗?也许第二个代码在某些情况下不起作用,那么使用第一个更好吗?

下面的会更好吗?

for (char *tempptr = x; *tempptr != '\0'; tempptr++)
4

8 回答 8

36
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)。

于 2010-08-02T13:17:29.773 回答
12

第一个代码在 i 的每次迭代中检查 x 的长度,找到最后一个 0 需要 O(n),所以需要 O(n^2),第二种情况是 O(n)

于 2010-08-02T13:10:40.427 回答
5

是的,您的第二个可能无法 100% 工作,但它会稍微完全正常。这是因为在使用 strlen() 时,您必须每次都调用该方法。更好的方法是这样

int strLength = strlen(x);
for (int i = 0; i < strLength; i++)

希望这可以帮助。

于 2010-08-02T13:13:59.320 回答
4

我可以假设在第一个变体中,您会在每次迭代中找到 strlen,而在第二个变体中,您不会这样做。
试试这个来检查:

int a = strlen(x); 
for (int i = 0; i < a; i++) {...}
于 2010-08-02T13:12:09.563 回答
2

我猜编译器可以优化(检查 Gregory Pakosz 评论)你的第一个 for 循环,这样你就会像这样:

int len = strlen(x);
for (int i = 0; i < len; i++)

这仍然是O(n)

无论如何,我认为你的第二个for循环会更快。

于 2010-08-02T13:12:53.610 回答
2

如果没有,则没有编译优化。是的,因为 strlen 每次都会迭代字符串的每个字节,而第二个实现只会执行一次。

于 2010-08-02T13:12:19.703 回答
0

值得注意的是,如果您不针对包含字符串的缓冲区大小测试索引,您可能会面临缓冲区溢出问题。根据您使用此代码所做的工作,这可能是一个实际问题,也可能不是,但进行额外检查很少会造成伤害,这是一个养成的好习惯。

我建议: for (i = 0; i < buf_size && x[i] != '\0'; i++)

在哪里:

  • buf_size是缓冲区的预定大小。如果x是一个数组,这将是sizeof(x); ifx是一个指针,你应该有可用的缓冲区大小。
  • 我已经i从循环中删除了声明,因为它只是有效的 c99。如果您只在 c99 下编译,请随时将其放回原处。
于 2010-08-02T17:22:36.820 回答
-1

当然,第一个比第二个需要更长的时间。他们实际上根本不做同样的事情——第一个是每次都计算字符串的长度;第二个是(有效地)只做一次。

第一个版本等价于:

for (int i=0; x[i] != 0; i++)
  for (int j=0; j<i; j++)
    ;

也许您的意思是“调用库 strlen() 比实现我自己的库更有效吗?” 答案当然是“视情况而定”。您的编译器可能具有 strlen() 的内在版本,这些版本的优化超出了您对源代码的期望,您可能位于函数调用昂贵的平台上(现在很少见),等等。

唯一既通用又正确的答案是“分析并找出答案”。

于 2010-08-02T13:13:55.253 回答