C++ C++;:斐波那契的三个递归实现。时间/空间的复杂性是什么?

C++ C++;:斐波那契的三个递归实现。时间/空间的复杂性是什么?,c++,recursion,time-complexity,tail-recursion,space-complexity,C++,Recursion,Time Complexity,Tail Recursion,Space Complexity,我对斐波那契序列的三个版本进行了编码,但我不太确定它们的时间/空间复杂性(以及原因): 变体1:头部递归 int fibonacci_h(int n) { if (n == 1 || n == 2) { return 1; } return fibonacci_h(n - 1) + fibonacci_h(n - 2); } int fibonacci_t(int n, int s_last = 0, int last = 1) { if (n == 1) {

我对斐波那契序列的三个版本进行了编码,但我不太确定它们的时间/空间复杂性(以及原因):

变体1:头部递归

 int fibonacci_h(int n) {
  if (n == 1 || n == 2) {
    return 1;
  }
  return fibonacci_h(n - 1) + fibonacci_h(n - 2);
}
int fibonacci_t(int n, int s_last = 0, int last = 1) {
  if (n == 1) {
    return last;
  }
  return fibonacci_t(n - 1, last, s_last + last);
}
变体2:尾部递归

 int fibonacci_h(int n) {
  if (n == 1 || n == 2) {
    return 1;
  }
  return fibonacci_h(n - 1) + fibonacci_h(n - 2);
}
int fibonacci_t(int n, int s_last = 0, int last = 1) {
  if (n == 1) {
    return last;
  }
  return fibonacci_t(n - 1, last, s_last + last);
}
变体3:带缓存的头递归

int fibonacci_hash(int n, unordered_map<int, int>* fib_hash = new unordered_map<int, int>{{1, 1},{2, 1}}) { 
  if((*fib_hash).find(n)!=((*fib_hash).end())){
    return  (*fib_hash)[n];
  }
  int result = fibonacci_hash(n - 1, fib_hash) + fibonacci_hash(n - 2, fib_hash);
  (*fib_hash)[n] = result;
  return result;
} 
int main() {
  int n = 10;
  cout << fibonacci_h(n) << endl;
  cout << fibonacci_t(n) << endl;
  cout << fibonacci_hash(n) << endl;
} // Output: 55
intfibonacci\u hash(intn,无序映射*fib\u hash=新的无序映射{{1,1},{2,1}){
if((*fib_hash.find(n)!=((*fib_hash.end())){
返回(*fib_hash)[n];
}
int result=fibonacci_散列(n-1,fib_散列)+fibonacci_散列(n-2,fib_散列);
(*fib_hash)[n]=结果;
返回结果;
} 
用法

int fibonacci_hash(int n, unordered_map<int, int>* fib_hash = new unordered_map<int, int>{{1, 1},{2, 1}}) { 
  if((*fib_hash).find(n)!=((*fib_hash).end())){
    return  (*fib_hash)[n];
  }
  int result = fibonacci_hash(n - 1, fib_hash) + fibonacci_hash(n - 2, fib_hash);
  (*fib_hash)[n] = result;
  return result;
} 
int main() {
  int n = 10;
  cout << fibonacci_h(n) << endl;
  cout << fibonacci_t(n) << endl;
  cout << fibonacci_hash(n) << endl;
} // Output: 55
intmain(){
int n=10;

cout进行天真递归的一个——你称之为头递归——是指数型的,O(2^n)。另外两个是O(n)。不过,记忆递归和尾递归都是O(n)空间。前者的哈希表大小是O(n),后者的调用堆栈深度是O(n),没有尾部递归优化。使用尾部递归优化,基本上是编译成迭代版本,其中O(n)时间和O(1)空间。

正如我所提到的-你的“头部”版本的时间复杂度是Θ((1+sqrt(5))/2)^n~=Θ(1.618^n)。这与

渐近地,(a+b)/a=a/b,即1+b/a=a/b;和(1+sqrt(5))/2是这个方程的解。显然,这也是海螺在自然界的特征

“head”版本的空间复杂度为Θ(n),因为这是由递归的最大深度决定的(每个级别的深度增加另一个恒定数量的局部变量和堆栈信息)


我忽略了进入单个整数的对数(n)位。也就是说,如果你想变得超级学究,你实际上应该用对数(n)时间乘以一切。

你是说:1.时间O(2^n)/空间O(n)(据我所知,指数函数的阶数是不等价的,所以你应该说什么样的指数函数对吗(n) /Space O(n)我不太确定这个例子的空间复杂度,因为tail不会使调用堆栈复合(基本情况的返回结果是所有链式递归调用的返回)。为什么这不是O(1)?3.时间O(n)/Space O(n)是的,tail递归调用不会是O(n)空间给定的尾部递归优化。但无论如何,就时间而言,1是O(2^n),另外两个是O(n)。所以在空间中:1.O(n)2.O(1)3.O(n)?说2.不是O(n),并不能确认它是O(1)。是的,如果你把堆栈作为“空间”的一部分计算我相信这是标准的,如果尾部递归的编译器使用尾部递归优化。你知道计算fibo(n)的另一种方法是迭代地做它,即O(n)时间O(1)空间。还有一种方法可以在log(n)中计算它时间使用比奈公式。第二个版本是从优化级别-O2向上。因此它将在恒定空间中运行。我不确定仅仅因为fibo(n)可以用phi^n近似,这意味着原始递归版本的运行时间是O(phi^n)。phi^n近似于fibo(n)的值但是这个值在递归实现中没有出现。我在声明2^n中得到2的地方是每个“级别”递归函数的递归调用次数将是以前级别的两倍。因此问题是将有多少个级别…这实际上类似于n的log base phi。因此运行时间更像是2^(log base phi of n)“该值在递归实现中不出现”