编写函数F(n)= 0.5F(n-1)

时间:2019-02-03 09:54:38

标签: c recursion time-complexity

  

让F(n)= 0.5F(n-1)和F(0)= 1

     

a。编写一个函数fun1,这是一个递归函数,用于评估n的项

     

b。编写一个函数fun2,这是一个非递归函数,用于评估n的项

     

c。 fun1的时间复杂度是多少,从哪个方面开始,就空间复杂度而言,使用fun1 vs fun2会更好

通常,该函数计算序列{1,1 / 2,1 / 4,1 / 8,...}的n个项

a。

 double fun1( int n ){
    if (n == 0)
        return 1;
    else
        return 0.5*fun1(n-1);
}

b。

double fun2( int n ){
    double sum = 1, i;
    for (i=0 ; i < n; i++)
        sum=sum*(0.5);
    return sum;
}

c。使用几何序列的总和直观地和数学上,我们可以证明它是O(n)

  1. 还有另一种方法吗?
  2. 如何解决空间复杂性?

4 个答案:

答案 0 :(得分:2)

fun1 fun2 的版本具有不同的空间复杂度,但它们的时间复杂度为 O(n)

但是,非递归函数也可以写成:

#import <math.h>

double fun2(int n) {
    return pow(0.5, n);
}

此函数具有时间和空间复杂度 O(1),并且对于大多数 n (可能是 n > 5),效率更高

对于最初的问题:这非常棘手,因为它取决于编译器的优化:

一个简单的实现是 fun1 ,它的空间复杂度是 O(n),因为调用 fun1(n)会有一个递归 n 的深度,因此需要堆栈上的 n 个调用帧。在大多数系统上,它最多只能使用某个 n 。然后,您会收到堆栈溢出错误,因为堆栈的大小有限。

优化的编译器将认识到它是一个尾递归函数,并将其优化为非常接近 fun2 的函数,其空间复杂度为 O(1)因为它使用固定数量的变量,且变量的大小独立于 n 并且没有递归。

答案 1 :(得分:1)

我知道这是一个家庭作业问题,因此我不会引用有关编译器优化和尾部递归的任何内容,因为这不是程序本身的属性,但是它是否取决于编译器是否会优化递归函数。.< / p>

您的第一种方法显然是O(n),因为它递归地调用f1并进行乘法。

您的第二种方法显然也是O(n),因为它只是一个简单的循环。 因此,对于时间复杂度,两者都是相同的O(n)

关于空间复杂度,fun1需要n个函数记录,所以它是O(n)空间复杂度,而fun2只需要一个变量,所以它是O(1)空间复杂度。因此对于空间复杂性,fun2是一种更好的方法。

答案 2 :(得分:1)

有关的递归和迭代逼近复杂度可以降低到 O(log n)的

以下溶液的递归深度是日志N

double fun3( int n ){

    double f;
    if ( n == 0 )
        return 1.0;

    f = fun3( n/2 );
    return f * f * (n % 2 ? 0.5 : 1.0);
}

迭代在下面的循环数目是日志N ,也:

double fun4( int n ){

    int i;
    double f = (n % 2 ? 0.5 : 1.0);
    for (i = n; i > 1; i /= 2)
        f *= 0.5*0.5;

    return f;
} 

答案 3 :(得分:0)

如果您查看生成的代码,您可以回答自己:https://godbolt.org/z/Gd9XxM

  1. 优化编译器很可能会删除尾递归。
  2. 空间和时间的复杂度在很大程度上取决于优化选项(尝试-Os,-O0)