[英]Manually calculating time complexity of recursive Fibonacci algorithm
我試圖理解遞歸Fibonacci算法的時間復雜度。
fib(n)
if (n < 2)
return n
return fib(n-1)+fib(n-2)
由於沒有太多的數學背景,我嘗試手工計算它。 也就是說,當n增加時,我手動計算步數。 我忽略了我認為是恆定時間的所有事情。 我就是這樣做的。 說我想計算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.
從這些方面來看,我認為運行時間可能是fib(n + 1)。 我不太確定1是否是常數因子,因為fib(n)和fib(n + 1)之間的差異可能非常大。
通常,樹遞歸過程所需的步驟數將與樹中的節點數成比例,而所需的空間將與樹的最大深度成比例。
在這種情況下,我相信樹中的節點數是fib(n + 1)。 所以我相信我是對的。 但是, 這段視頻讓我困惑:
所以這是一個時間復雜度實際上是順序的東西,結果是n的斐波那契。 有一種東西像Fibonacci數字一樣增長。
...
必須檢查此樹中的每個節點。
我絕對感到震驚。 我已經檢查了樹中的所有節點,並且總是有fib(n + 1)個節點,因此計算fib(n)時的步數。 我無法弄清楚為什么有些人說它是fib(n)步數而不是fib(n + 1)。
我究竟做錯了什么?
在您的程序中,您有這個耗時的操作(按每個操作使用的時間排序,在列表頂部快速操作):
讓我們看一下這些動作的執行次數,並將其與n和fib(n)進行比較:
n | fib | #ADD | #IF | #RET | #CALL
---+-----+------+-----+------+-------
0 | 0 | 0 | 1 | 1 | 0
1 | 1 | 0 | 1 | 1 | 0
對於n≥2,您可以這樣計算數字:
為什么?
所以,這是你的其他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
您可以看到,添加的數量恰好是函數調用數量的一半(好吧,您也可以直接從代碼中讀取它)。 如果將初始程序調用計為第一個函數調用,那么您具有完全相同的IF,返回和調用量。
因此,您可以將1個ADD,2個IF,2個RET和2個CALL組合到一個需要恆定時間的超級動作中。
您還可以從列表中讀取,添加數量比fib(n + 1)少1(可以忽略)。
因此,運行時間是有序的fib(n+1)
。
fib(n+1) / fib(n)
的比率越接近Φ越大,n越大。 Φ是黃金比例,即1.6180338997是常數。 並且在訂單中忽略常數因子。 這樣,順序O(fib(n+1))
是完全一樣O(fib(n))
現在讓我們來看看空間:
確實,處理樹所需的最大空間等於樹與最大遠葉之間的最大距離。 這是事實,因為你在f(n-1)返回后調用f(n-2)。
所以你的程序所需的空間是n
階。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.