c - 函数的运行时间

标签 c runtime big-o time-complexity

令函数 f() 为:

void f(int n)
{
   for (int i=1; i<=n; i++)
     for (int j=1; j<=n*n/i; j+=i)
       printf(“*”);
}

根据我的计算,Big O 方法的运行时间应该是 O(n2log n)。
答案是 O(n2)。这是为什么?

最佳答案

我欠你一个道歉。我第一次看错了你的代码,所以我最初给出的答案是不正确的。这是一个更正的答案,以及与原始答案的比较,解释了我的分析哪里出了问题。我希望您觉得这很有趣 - 我认为由此产生了一些非常酷的数学!

您发布的代码显示在此处:

for (int i=1; i<=n; i++)
  for (int j=1; j<=n*n/i; j+=i)
     printf(“*”);

为了确定这段代码的运行时间,让我们看看内部循环在所有迭代中做了多少工作。当 i = 1 时,循环计数到 n2 个,因此它执行 n2 工作。当 i = 2 时,循环计数到 n2/2,因此它执行 n2/4。当 i = 3 时,循环以三为单位计数到 n2/3,因此它执行 n2/9。更一般地,第 k 次迭代执行 n2/k2 工作,因为它以大小为 k 的步长计数到 n2/k。

如果我们总结这里为 i 从 1 到 n(含)所做的工作,我们看到运行时是

n2 + n2 / 4 + n2 / 9 + n2 / 16 + ... + n2 / n2

= n2 (1 + 1/4 + 1/9 + 1/16 + 1/25 + ... + 1/n2).

此处的总和 (1 + 1/4 + 1/9 + 1/16 + ...) 具有(令人惊讶的!)属性,在极限情况下,it's exactly equal to π2 / 6.换句话说,您的代码的运行时间渐近地接近 n2 π/6,因此运行时间为 O(n2)。您可以通过编写一个程序将实际步数与 n2 π/6 进行比较并查看结果来了解这一点。

我第一次弄错了,因为我误读了你的代码,就好像它是这样写的一样

for (int i=1; i<=n; i++)
  for (int j=1; j<=n*n/i; j+=1)
     printf(“*”);

换句话说,我认为内部循环在每次迭代中采用大小为 1 的步长,而不是大小为 i 的步长。在那种情况下,循环的第 k 次迭代完成的工作是 n2/k,而不是 n2/k2,这运行时间为

n2 + n2/2 + n2/3 + n2/4 + ...n2/n

= n2(1 + 1/2 + 1/3 + 1/4 + ... + 1/n)

在这里,我们可以利用 1 + 1/2 + 1/3 + ... + 1/n 是众所周知的求和这一事实。第 n 个 harmonic number定义为 Hn = 1 + 1/2 + 1/3 + ... + 1/n 并且已知谐波数服从 Hn = Θ( log n),所以这个版本的代码运行时间为 O(n2 log n)。有趣的是,这种变化如此显着地改变了代码的运行时间!

作为一个有趣的概括,让我们假设您更改内部循环,以便步长为 iε 对于某些 ε > 0(并假设您四舍五入)。在这种情况下,第 k 次通过内部循环的迭代次数将为 n2/k1 + ε,因为循环的上限为 n< sup>2/k,你的步数为 kε。通过与我们之前看到的类似的分析,运行时将是

n2 + n2 / 21+ε + n2 / 31+ε + n2 / 31+ε + ... + n2 / n1+ε

= n2(1 + 1/21+ε + 1/31+ε + 1/41+ε + ... + 1/n1+ε)

如果你上过微积分类(class),你可能会认识到这个系列

1 + 1/21+ε + 1/31+ε + 1/41+ε + ... + 1/n1+ε

收敛到任何 ε > 0 的某个固定限制,这意味着如果步长是 i 的任何正幂,则总运行时间将为 O(n2 ).这意味着以下所有代码片段的运行时间为 O(n2):

for (int i=1; i<=n; i++)
  for (int j=1; j<=n*n/i; j+=i)
     printf(“*”);

for (int i=1; i<=n; i++)
  for (int j=1; j<=n*n/i; j+=i*i)
     printf(“*”);

for (int i=1; i<=n; i++)
  for (int j=1; j<=n*n/i; j+=i*(sqrt(i) + 1))
     printf(“*”);

关于c - 函数的运行时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35383741/

相关文章:

objective-c - 是否可以使用 Objective-C 运行时特性来确定从何处调用方法?

algorithm - 大O,算法分析

python - 在 O(m*log m) 中计算 'initial lists' 的算法

c - 分配后如何检查char指针是否指向任何内容

c - 可能(x)和 __builtin_expect((x),1)

c - 没有参数的 `printf("%p")` 是什么意思

在 C++ 中计算行列式

.net - 调试混淆的 .Net 程序集

找不到这段 C 代码的时间复杂度?

data-structures - 哪种数据结构的搜索和插入功能速度最快?