简体   繁体   English

递归斐波那契的 Big O 的非数学解释是什么?

[英]What is a non-mathematical explanation for the Big O of recursive fibonacci?

I read both articles on Big O for Recursive Fibonacci sequence but still do not have a conceptual understanding of why it is O(2^n) .我阅读了关于递归斐波那契数列的 Big O 的两篇文章,但仍然没有概念性地理解为什么它是O(2^n)

This is not a duplicate of this link .这不是此链接的副本。 Please don't mark as a duplicate.请不要标记为重复。 I'm looking for a conceptual answer .我正在寻找一个概念性的答案

This is one of the simplest recursive functions out there and I want to understand how to look at it and determine the the Big O without complex math and proofs.这是最简单的递归函数之一,我想了解如何看待它并在没有复杂数学和证明的情况下确定大 O。

// O(2^n)
function fiboR(n){
  if( n === 0 || n === 1 ){
    return n;
  } else if ( n >=2 ){
    return fiboR(n-1) + fiboR(n-2);
  }
}

For example Big O for the iterative version is O(n) .例如,迭代版本的 Big O 是O(n) I can just look and see that as n increases the while loop iterations increase linearly.我可以看看,随着 n 的增加,while 循环迭代线性增加。 No complex math or long proofs needed.不需要复杂的数学或冗长的证明。

// O(n)
function fibo(n){
  let prev0 = 0;
  let prev1 = 1;
  if( n === 0 || n === 1 ){
    return n;
  }
  while( n-- >= 2){
    sum = prev0 + prev1;
    prev0 = prev1;
    prev1 = sum;
  }
  return sum;
}

A good number of naive recursive functions have exponential complexity, so this is good intuition to keep in mind.大量朴素的递归函数具有指数级复杂性,因此要牢记这一点。

Consider this function:考虑这个函数:

function fiboR1(n){
  if( n === 0 || n === 1 ){
    return n;
  } else if ( n >=2 ){
    return fiboR1(n-1) + fiboR1(n-1);
  }
}

Okay, so fiboR1 doesn't actually compute the Fibonacci sequence.好的,所以fiboR1实际上并不计算斐波那契数列。 That doesn't matter.那没关系。 Notice that its asymptotic complexity will be at least that of fiboR .请注意,它的渐近复杂度至少是fiboR复杂度。 This is because the two recursive calls to fiboR1(n-1) are more expensive than one call to fiboR(n-1) and one call to fiboR(n-2) .这是因为对fiboR1(n-1)的两次递归调用比对fiboR(n-1)和对fiboR(n-2)一次调用更昂贵。 So let's think about what the complexity of fiboR1 is.那么让我们想想fiboR1的复杂度是fiboR1

Let's consider an example call to fiboR1(100) .让我们考虑对fiboR1(100)的示例调用。

fiboR1(100) = 2 * fiboR1(99)
            = 4 * fiboR1(98)
            = 8 * fiboR1(97)
            = 16 * fiboR1(96)
            = 32 * fiboR1(95)
            = 64 * fiboR1(94)
            ...

See the pattern now?现在看到模式了吗? We have O(2^n) recursive calls to fiboR1 , and each call is a constant time branch.我们对fiboR1进行了O(2^n)递归调用,每次调用都是一个恒定时间分支。 So fiboR1 is O(2^n) , which means that by extension, fiboR is also O(2^n) , as big-O is an upper-bound function.所以fiboR1O(2^n) ,这意味着通过扩展, fiboR也是O(2^n) ,因为 big-O 是一个上限函数。

If you know the closed form for the Fibonacci sequence, we can also just do this example for fiboR directly.如果你知道斐波那契数列的封闭形式,我们也可以直接为fiboR做这个例子。 Let's consider fiboR(100) :让我们考虑fiboR(100)

fiboR(100) = fiboR(99) + fiboR(98)
           = 2 * fiboR(98) + fiboR(97)
           = 3 * fiboR(97) + 2 * fiboR(96)
           = 5 * fiboR(96) + 3 * fiboR(95)
           = 8 * fiboR(95) + 5 * fiboR(94)
           = 13 * fiboR(94) + 8 * fiboR(93)
           ...

The number of recursive function calls follows the Fibonacci sequence.递归函数调用的次数遵循斐波那契数列。 The closed form for the Fibonacci sequence is exponential in n .斐波那契数列的封闭形式在n呈指数。 In fact, it is O(((1+sqrt{5})/2)^n) , which is about O(1.6^n) .事实上,它是O(((1+sqrt{5})/2)^n) ,大约是O(1.6^n)

It is simple to calculate by diagraming function calls.通过绘制函数调用图来计算很简单。 Simply add the function calls for each value of n and look at how the number grows.只需为 n 的每个值添加函数调用,然后查看数字如何增长。

The Big O is O(Z^n) where Z is the golden ratio or about 1.62.大 O 是 O(Z^n),其中 Z 是黄金比例或大约 1.62。

Both the lenoardo numbers and the fibonacci numbers aproach this ratio as we increase n.当我们增加 n 时,雷诺数和斐波那契数都接近这个比率。

2 (2 -> 1, 0)

4 (3 -> 2, 1) (2 -> 1, 0)

8 (4 -> 3, 2) (3 -> 2, 1) (2 -> 1, 0)
            (2 -> 1, 0)


14 (5 -> 4, 3) (4 -> 3, 2) (3 -> 2, 1) (2 -> 1, 0)
            (2 -> 1, 0)

            (3 -> 2, 1) (2 -> 1, 0)

22 (6 -> 5, 4)
            (5 -> 4, 3) (4 -> 3, 2) (3 -> 2, 1) (2 -> 1, 0)
                        (2 -> 1, 0)

                        (3 -> 2, 1) (2 -> 1, 0)

            (4 -> 3, 2) (3 -> 2, 1) (2 -> 1, 0)
                        (2 -> 1, 0)

Assuming you accept that the function is correct, ie that it does calculate the Fibonacci numbers, then it is very easy to show that its running time must be exponential: it only returns 0 or 1 in the base case, and it only produces larger results by adding smaller results together.假设您接受该函数是正确的,即它确实计算了斐波那契数,那么很容易证明它的运行时间必须是指数级的:它在基本情况下只返回 0 或 1,并且只产生更大的结果通过将较小的结果相加。

Since the Fibonacci numbers grow exponentially, the only way you could make them by adding a lot of 1s together is by adding exponentially many 1s.由于斐波那契数以指数方式增长,因此通过将许多 1 相加来制作它们的唯一方法就是以指数方式添加许多 1。 Each result only gets added to the final total once, so the base case must be executed exponentially many times to produce all of those 1s as different results.每个结果只会添加到最终总数中一次,因此必须以指数方式多次执行基本情况才能将所有这些 1 生成为不同的结果。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM