让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)
答案 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