简体   繁体   English

手动计算递归Fibonacci算法的时间复杂度

[英]Manually calculating time complexity of recursive Fibonacci algorithm

I am trying to understand the time complexity of the recursive Fibonacci algorithm. 我试图理解递归Fibonacci算法的时间复杂度。

fib(n)
    if (n < 2)
        return n
    return fib(n-1)+fib(n-2)

Having not much mathematical background, I tried computing it by hand. 由于没有太多的数学背景,我尝试手工计算它。 That is, I manually count the number of steps as n increases. 也就是说,当n增加时,我手动计算步数。 I ignore all things that I think are constant time. 我忽略了我认为是恒定时间的所有事情。 Here is how I did it. 我就是这样做的。 Say I want to compute fib(5). 说我想计算fib(5)。

n = 0 - just a comparison on an if statement. This is constant.
n = 1 - just a comparison on an if statement. This is constant.
n = 2 - ignoring anything else, this should be 2 steps, fib(1) takes 1 step and fib(0) takes 1 step.
n = 3 - 3 steps now, fib(2) takes two steps and fib(1) takes 1 step.
n = 4 - 5 steps now, fib(3) takes 3 steps and fib(2) takes 2 steps.
n = 5 - 8 steps now, fib(4) takes 5 steps and fib(3) takes 3 steps.

Judging from these, I believe the running time might be fib(n+1). 从这些方面来看,我认为运行时间可能是fib(n + 1)。 I am not so sure if 1 is a constant factor because the difference between fib(n) and fib(n+1) might be very large. 我不太确定1是否是常数因子,因为fib(n)和fib(n + 1)之间的差异可能非常大。

I've read the following on SICP : 我在SICP上阅读了以下内容

In general, the number of steps required by a tree-recursive process will be proportional to the number of nodes in the tree, while the space required will be proportional to the maximum depth of the tree. 通常,树递归过程所需的步骤数将与树中的节点数成比例,而所需的空间将与树的最大深度成比例。

In this case, I believe the number of nodes in the tree is fib(n+1). 在这种情况下,我相信树中的节点数是fib(n + 1)。 So I am confident I am correct. 所以我相信我是对的。 However, this video confuses me: 但是, 这段视频让我困惑:

So this is a thing whose time complexity is order of actually, it turns out to be Fibonacci of n. 所以这是一个时间复杂度实际上是顺序的东西,结果是n的斐波那契。 There's a thing that grows exactly as Fibonacci numbers. 有一种东西像Fibonacci数字一样增长。

... ...

That every one of these nodes in this tree has to be examined. 必须检查此树中的每个节点。

I am absolutely shocked. 我绝对感到震惊。 I've examined all nodes in the tree and there are always fib(n+1) nodes and thus number of steps when computing fib(n). 我已经检查了树中的所有节点,并且总是有fib(n + 1)个节点,因此计算fib(n)时的步数。 I can't figure out why some people say it is fib(n) number of steps and not fib(n+1). 我无法弄清楚为什么有些人说它是fib(n)步数而不是fib(n + 1)。

What am I doing wrong? 我究竟做错了什么?

In your program, you have this time-consuming actions (sorted by time used per action, quick actions on top of the list): 在您的程序中,您有这个耗时的操作(按每个操作使用的时间排序,在列表顶部快速操作):

  • Addition 加成
  • IF (conditional jump) IF(条件跳转)
  • Return from subroutine 从子程序返回
  • Function call 函数调用

Lets look at how many of this actions are executed, and lets compare this with n and fib(n): 让我们看一下这些动作的执行次数,并将其与n和fib(n)进行比较:

 n | fib | #ADD | #IF | #RET | #CALL  
---+-----+------+-----+------+-------
 0 |   0 |    0 |   1 |    1 |     0
 1 |   1 |    0 |   1 |    1 |     0

For n≥2 you can calculate the numbers this way: 对于n≥2,您可以这样计算数字:

  • fib(n) = fib(n-1) + fib(n-2) fib(n)= fib(n-1)+ fib(n-2)
  • ADD(n) = 1 + ADD(n-1) + ADD(n-2) ADD(n)= 1 + ADD(n-1)+ ADD(n-2)
  • IF(n) = 1 + IF(n-1) + IF(n-2) IF(n)= 1 + IF(n-1)+ IF(n-2)
  • RET(n) = 1 + RET(n-1) + RET(n-2) RET(n)= 1 + RET(n-1)+ RET(n-2)
  • CALL(n) = 2 + CALL(n-1) + CALL(n-2) CALL(n)= 2 + CALL(n-1)+ CALL(n-2)

Why? 为什么?

  • ADD: One addition is executed directly in the top instance of the program, but in the both subroutines, that you call are also additions, that need to be executed. ADD:一个加法直接在程序的顶层实例中执行,但在这两个子程序中,您调用的也是需要执行的附加项。
  • IF and RET: Same argument as before. IF和RET:与以前相同的参数。
  • CALL: Also the same, but you execute two calls in the top instance. CALL:也是一样,但你在顶层实例中执行两次调用。

So, this is your list for other values of n: 所以,这是你的其他n值列表:

  n |    fib |   #ADD |    #IF |   #RET |  #CALL  
 ---+--------+--------+--------+--------+--------
  0 |      0 |      0 |      1 |      1 |      0
  1 |      1 |      0 |      1 |      1 |      0
  2 |      1 |      1 |      3 |      3 |      2
  3 |      2 |      2 |      5 |      5 |      4
  4 |      3 |      4 |      9 |      9 |      8
  5 |      5 |      7 |     15 |     15 |     14
  6 |      8 |     12 |     25 |     25 |     24
  7 |     13 |     20 |     41 |     41 |     40
  8 |     21 |     33 |     67 |     67 |     66
  9 |     34 |     54 |    109 |    109 |    108
 10 |     55 |     88 |    177 |    177 |    176
 11 |     89 |    143 |    287 |    287 |    286
 12 |    144 |    232 |    465 |    465 |    464
 13 |    233 |    376 |    753 |    753 |    752
 14 |    377 |    609 |   1219 |   1219 |   1218
 15 |    610 |    986 |   1973 |   1973 |   1972
 16 |    987 |   1596 |   3193 |   3193 |   3192
 17 |   1597 |   2583 |   5167 |   5167 |   5166
 18 |   2584 |   4180 |   8361 |   8361 |   8360
 19 |   4181 |   6764 |  13529 |  13529 |  13528
 20 |   6765 |  10945 |  21891 |  21891 |  21890
 21 |  10946 |  17710 |  35421 |  35421 |  35420
 22 |  17711 |  28656 |  57313 |  57313 |  57312
 23 |  28657 |  46367 |  92735 |  92735 |  92734
 24 |  46368 |  75024 | 150049 | 150049 | 150048
 25 |  75025 | 121392 | 242785 | 242785 | 242784
 26 | 121393 | 196417 | 392835 | 392835 | 392834
 27 | 196418 | 317810 | 635621 | 635621 | 635620

You can see, that the number of additions is exactly the half of the number of function calls (well, you could have read this directly out of the code too). 您可以看到,添加的数量恰好是函数调用数量的一半(好吧,您也可以直接从代码中读取它)。 And if you count the initial program call as the very first function call, then you have exactly the same amount of IFs, returns and calls. 如果将初始程序调用计为第一个函数调用,那么您具有完全相同的IF,返回和调用量。

So you can combine 1 ADD, 2 IFs, 2 RETs and 2 CALLs to one super-action that needs a constant amount of time. 因此,您可以将1个ADD,2个IF,2个RET和2个CALL组合到一个需要恒定时间的超级动作中。

You can also read from the list, that the number of Additions is 1 less (which can be ignored) than fib(n+1). 您还可以从列表中读取,添加数量比fib(n + 1)少1(可以忽略)。

So, the running time is of order fib(n+1) . 因此,运行时间是有序的fib(n+1)

The ratio fib(n+1) / fib(n) gets closer and closer to Φ, the bigger n grows. fib(n+1) / fib(n)的比率越接近Φ越大,n越大。 Φ is the golden ratio, ie 1.6180338997 which is a constant. Φ是黄金比例,即1.6180338997是常数。 And constant factors are ignored in orders. 并且在订单中忽略常数因子。 So, the order O(fib(n+1)) is exactly the same as O(fib(n)) . 这样,顺序O(fib(n+1))是完全一样O(fib(n))


Now lets look at the space: 现在让我们来看看空间:

It is true, that the maximum space, needed to process a tree is equal to the maximum distance between the tree and the maximum distant leaf. 确实,处理树所需的最大空间等于树与最大远叶之间的最大距离。 This is true, because you call f(n-2) after f(n-1) returned. 这是事实,因为你在f(n-1)返回后调用f(n-2)。

So the space needed by your program is of order n . 所以你的程序所需的空间是n阶。

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

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