什麼是遞歸:函數內部調用函數自身。
什麼是斐波那契數列:1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89......像這樣的數列,第一個數加第二個數等於第三個數,第二個數加第三個數等於第四個數,以這樣的規律遞推。F(1)=1,F(2)=1, F(n)=F(n - 1)+F(n - 2)(n ≥ 3,n ∈ N*)
現在我將用Python來寫遞歸實現斐波那契數列。
def fibonacci(n): # n表示計算斐波那契數列數列中的哪個數
if n in [1, 2]:
return 1
return fibonacci(n-1) + fibonacci(n-2)
if __name__ == "__main__":
fibonacci(5)
好了這樣就實現了,就只用了這麼點點的代碼就完成了通過遞歸計算出斐波那契數列中處於任何位置的數。看似很簡單,但是背後的運行其實是很繁瑣的。接下來會慢慢揭曉。
我們先來看看執行所需時間:
我們計算斐波那契數列的第30位數:
def fibonacci(n): # n(n>0)表示計算斐波那契數列數列中的哪個數
if n in [1, 2]:
return 1
return fibonacci(n-1) + fibonacci(n-2)
if __name__ == "__main__":
start_time = datetime.now()
fib_num = fibonacci(30)
end_time = datetime.now()
print("------------------------------")
print("當前數爲:", fib_num)
print("耗時:", (end_time-start_time).total_seconds())
print("------------------------------")
運行結果爲:
再計算第31位(將代碼中的參數改爲31):
再計算第32位(將代碼中的參數改爲32):
再計算第33位(將代碼中的參數改爲33):
再計算第34位(將代碼中的參數改爲34):
再計算第35位(將代碼中的參數改爲35):
再計算第36位(將代碼中的參數改爲36):
再來計算第40位看看,跳了4位(將代碼中的參數改爲40):
我們仔細觀察這些計算耗時,我們發現,每計算多一位數,所耗時間急劇上升,幾乎翻倍,這是爲什麼呢?其實是由於做了大量重複的計算。我們看圖說話:
上圖是使用遞歸計算斐波那契數列的第七個數,我們可以看到,f7=f6+f5,f6=f5+f4......這樣依次傳遞,直到最後得出f1或者f2就開始返回(return,歸),這樣最終計算出f7,但是我們可以看到,有大量重複的計算過程,比如:進行了5次f1+f2,進行了3次f2+f3......這還只是計算第七個數,如果計算更大的數,計算量會成幾何倍增加,我們接下來修改代碼試試計算斐波那契數列的第30個數,看看計算次數統計:
from datetime import datetime
total_num = 0 # 統計一共進行了多少次遞歸
total_dict = {} # 統計每個的計算次數
def fibonacci(n): # n(n>0)表示計算斐波那契數列數列中的哪個數
if n in [1, 2]:
return 1
global total_num
total_num += 1
if n not in total_dict:
total_dict[n] = 1
else:
total_dict[n] += 1
return fibonacci(n-1) + fibonacci(n-2)
if __name__ == "__main__":
start_time = datetime.now()
fib_num = fibonacci(30)
end_time = datetime.now()
print("------------------------------")
print("當前數爲:", fib_num)
print("耗時:", (end_time-start_time).total_seconds())
print("執行遞歸次數:", total_num)
print("各個數的計算次數統計:", total_dict)
print("------------------------------")
運行結果爲:
我們可以看到,斐波那契數列的第30個數是832040,運行耗時爲0.302508秒,一共進行了832039次遞歸,再來看看各個數的計算次數統計,字典的key表示計算的斐波那契數列中的第幾個數,value表示計算了多少次,比如8:28657,8表示斐波那契數列的第8個數,28657表示斐波那契數列的第8個數一共計算了28657次,即進行了28657次f7+f6。由於計算次數大量重複,導致消耗時間成幾何倍增長。
上面是斐波那契數列的第30個數,我們再來看看斐波那契數列的31個數的運行結果:
對比後看看,各項數據有很大的差距。因此,按照這樣的遞歸計算斐波那契數列是十分耗時並且不穩定的。