【问题标题】:What is the complexity of this c function这个c函数的复杂度是多少
【发布时间】:2010-12-25 06:43:35
【问题描述】:

以下c函数的复杂度是多少?

double foo (int n) {
    int i;
    double sum;
    if (n==0) return 1.0;
    else {
        sum = 0.0;
        for (i =0; i<n; i++)
        sum +=foo(i);
        return sum;
    }
}

请不要只发布复杂性,您能帮助我了解如何去做吗?

编辑:这是考试中提出的客观问题,提供的选项是 1.O(1) 2.O(n) 3.O(n!) 4.O(n^n)

【问题讨论】:

  • 这是一个在考试中提出的客观问题,提供的选项是 1. O(1) 2.O(n) 3.O(n!) 4.O(n^n)
  • @Bunny Rabbit,可能是你的老师不熟悉 O 表示法 3.O(n!) 4.O(n^n) 是真的,它也是 O(2^n) 和实际上是 Teta(2^n)
  • 我猜关键是要选择最紧的界限
  • 嗯,你没有对 O(n!) 给出任何解释 :( :(
  • @Bunny Rabbit,查看我的更新。

标签: c algorithm complexity-theory


【解决方案1】:

这是 Θ(2^n)(假设 f 是我们所拥有的算法的运行时间):

f(n) = f(n-1) + f(n-2) + ... + 1
f(n-1) = f(n-2) + f(n-3) + ...
==> f(n) = 2*f(n-1), f(0) = 1
==> f(n) is in O(2^n)

其实如果我们忽略常量操作,准确的运行时间是2n

如果你写的是考试,O(n!) 和 O(n^n) 都是正确的,其中最接近 Θ(2^n) 的答案是 O(n!),但是如果我是学生,我会标记他们两个:)


O(n!) 的解释:

for all n >= 1: n! = n(n-1)...*2*1 >= 2*2*2*...*2 = 2^(n-1) ==>
2 * n! >= 2^n ==> 2^n is in O(n!),
Also n! <= n^n for all n >= 1 so n! is in O(n^n)

So O(n!) in your question is nearest acceptable bound to Theta(2^n)

【讨论】:

  • 实际上,wolfram alpha 告诉我它正好是 2^n 但是嘿,详细信息:P
【解决方案2】:

一方面,它的编码很差:)

double foo (int n) {         // foo return a double, and takes an integer parameter
    int i;                   // declare an integer variable i, that is used as a counter below
    double sum;              // this is the value that is returned
    if (n==0) return 1.0;    // if someone called foo(0), this function returns 1.0
    else { // if n != 0
        sum = 0.0;           // set sum to 0
        for (i =0; i<n; i++) // recursively call this function n times, then add it to the result
        sum +=foo(i);
        return sum;          // return the result
    }
}

你正在调用 foo() 类似 n^n 的东西(你将 n 向下舍入到最接近的整数)

例如:

foo(3) 将被调用 3^3 次。

祝你好运,圣诞快乐。

编辑:哎呀,刚刚更正了一些东西。为什么 foo 返回一个双精度值?它总是返回一个整数,而不是双精度。

这将是一个更好的版本,带有微优化! :D

int foo(int n)
{
    if(n==0) return 1;
    else{
        int sum = 0;
        for(int i = 0; i < n; ++i)
        sum += foo(i);
        return sum;
    }
}

【讨论】:

  • "为什么 foo 返回双倍?"因为,是双倍的。 (重言式 FTW!)
  • 将 sum 转换为 int 将是完全相同的值。通过使用 int 而不是 double,您可以占用 4 个字节的内存而不是 8 个字节。 i 加一,与 n 进行比较,因此函数总是以整数作为参数递归调用。它永远不需要返回一个双精度数,除非你正在做超负数或正数。
  • 当然,负数有一个例外。它不会递归调用,因为 i 总是大于 n。
【解决方案3】:

你本来可以更清楚一点... grumble grumble

<n = ?> : <return value> : <number of times called>
n = 0 : 1 : 1
n = 1 : 1 : 2
n = 2 : 2 : 4
n = 3 : 4 : 8
n = 4 : 8 : 16
n = 5 : 16 : 32
n = 6 : 32 : 64
n = 7 : 64 : 128
n = 8 : 128 : 256
n = 9 : 256 : 512
n = 10 : 512 : 1024

number_of_times_call = pow(2, n-1);

让我们尝试输入,好吗?

使用此代码:

#include <iostream>

double foo (int n) {
    int i;
    double sum;
    if (n==0) return 1.0;
    else {
        sum = 0.0;
        for (i =0; i<n; i++)
        sum +=foo(i);
        return sum;
    }
}


int main(int argc, char* argv[])
{
    for(int n = 0; 1; n++)
    {
       std::cout << "n = " << n << " : " << foo(n);
       std::cin.ignore();
 }

    return(0);
}

我们得到:

n = 0 : 1
n = 1 : 1
n = 2 : 2
n = 3 : 4
n = 4 : 8
n = 5 : 16
n = 6 : 32
n = 7 : 64
n = 8 : 128
n = 9 : 256
n = 10 : 512

因此可以简化为:

double foo(int n)
{
    return((double)pow(2, n));
}

【讨论】:

  • 不错的答案,但非常偏离主题。
  • @Juan OP 不够清楚......至少,当我第一次看到这个问题时。大多数情况下,我看到的只是代码和“你能解释一下吗”,或者类似的东西。
【解决方案4】:

函数由多个部分组成。

第一个复杂性是if(n==0)return 1.0;,因为它只会生成一次运行。那将是O(1)

下一部分是for(i=0; i&lt;n; i++) 循环。因为从0..n循环它是O(n)

除了递归之外,对于n 中的每个数字,您都会再次运行该函数。并在该函数中再次循环和下一个函数。等等……

要弄清楚它会是什么,我建议您在循环内添加一个全局计数器,这样您就可以看到它针对某个数字执行了多少次。

【讨论】:

  • 查看我的回答执行次数。