小甲魚零基礎學習python_13 【遞歸實現:遞歸和斐波那契兔崽們的漢諾塔之謎】


遞歸

有人說,天才使用遞歸,因爲遞歸大大的減少了程序員的代碼量,而且能方便程序員實現許多的功能,但從內存等角度上,比如數據結構裏提到的空間複雜度和時間複雜度來說,遞歸算法很多情況下的時間複雜度往往是很大的,並稱不上一個好的算法,但是遞歸在某些方面,卻又有別的方式無法媲美的優點,今天舉三個例子,來溫習前幾天學習的遞歸。

1. 階乘的兩種實現:

#非遞歸:
def  jiecheng(n):
    y=1
    for i in range(1,n+1):     #range值取不到stop值本身,故加一
        y*=i
    return y


#遞歸實現:
#提前在程序開頭import sys
sys.setrecursionlimit(100)   #設置最大遞歸層數爲100 是一個python的保護措施

def jiecheng2(x):
    if x==0:       #0的階乘爲1
        y=1
    else:
        y=x*jiecheng2(x-1)
    return y

下面用求6000的階乘對比一下兩種算法的優劣:
非遞歸:
這裏寫圖片描述
圖片僅爲結果的一小部分,但是結果僅在一眨眼的情況下就運行出來了

遞歸:
這裏寫圖片描述
可以看到,這裏遞歸6000層,超過了我開頭設置的100層,所以我們把遞歸允許層數設置大一點,再來嘗試一下:

import sys
sys.setrecursionlimit(10000)    #設置最大遞歸層數爲10000

這裏寫圖片描述

Process finished with exit code -1073741571 (0xC00000FD)
查看問題的根源在於遞歸導致的棧溢出

解決辦法可參考:誰說Python不能尾遞歸優化


2. 斐波那契數列的兩種實現:


#斐波那契數列 F(n) =  1(n=1,2) ; F(n-1)+F(n-2)


# 遞歸實現
def fibonacci(n):

    if(n<1):
        print('請重新輸入!不可小於1!')
        y=-1
    elif(n==1):
        y=1
    elif n==2:
        y=1
    else:
        y=fibbonacci(n-1)+fibbonacci(n-2)
    return y


n=int(input('請輸入幾個月:\n'))
print('遞歸', n, ' 個月後共有:', fibonacci(n), ' 對兔子')






# 非遞歸實現
def fab(n):
    if(n<1):
        print('請重新輸入!不可小於1!')
        y=-1
    elif(n==1):
        y=1
    elif n==2:
        y=1
    else:
        n1=1
        n2=1
        n3=1
        while(n-2>0):
            n3=n2+n1
            n1=n2
            n2=n3
            n-=1
        y=n3
    return y

print('非遞歸:20個月後共有:', fab(20), ' 對兔子')

這裏寫圖片描述

對於斐波那契數列的遞歸和非遞歸算法進行測試,仍然是非遞歸比較優越。
但是這麼說我們的遞歸方法,除了減少程序的代碼量,就真的別無用處了嗎?當然不是!
請看我們的著名的漢諾塔算法:


3. 漢諾塔的遞歸實現:

遞歸的正確使用 – 漢諾塔

第一個參數是起始柱,第二個參數是過渡柱,第三個參數是終點柱
def hanoi(n,x,y,z):
    if n==1:
        print(x, '-->', z)
    else:
        hanoi(n - 1, x, z, y) #將前n-1從x移動到y上
        print(x,'-->',z) #將最一個盤子從x移動到z上
        hanoi(n - 1, y, x, z)  #將前n-1從y移動到z上
        # 注意以上兩次遞歸調用漢諾塔算法,起始柱,過渡柱,目標柱的變化!
n=int(input('請輸入漢諾塔的層數:\n'))
hanoi(n,'x','y','z')

這裏寫圖片描述

遞歸大大的減少了程序員的代碼量,而且能方便程序員實現許多的功能,但是也比較喫內存喫時間,要在內存,時間和算法之間尋求一個平衡點,遞歸的用法還需斟酌再三,但我認爲不一定是天才纔可用遞歸,相信我們多學多練,也能找到那個平衡點的!


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章