Python之遞歸函數

Python之遞歸函數

在函數內部,能夠調用其餘函數。若是一個函數在內部調用自身自己,這個函數就是遞歸函數。數據結構

舉個例子,咱們來計算階乘 n! = 1 * 2 * 3 * ... * n,用函數 fact(n)表示,能夠看出:ide

fact(n) = n! = 1 * 2 * 3 * ... * (n-1) * n = (n-1)! * n = fact(n-1) * n

因此,fact(n)能夠表示爲 n * fact(n-1),只有n=1時須要特殊處理。函數

因而,fact(n)用遞歸的方式寫出來就是:code

def fact(n):
    if n==1:
        return 1
    return n * fact(n - 1)

上面就是一個遞歸函數。能夠試試:htm

>>> fact(1)
1
>>> fact(5)
120
>>> fact(100)
93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000L

若是咱們計算fact(5),能夠根據函數定義看到計算過程以下:遞歸

===> fact(5)
===> 5 * fact(4)
===> 5 * (4 * fact(3))
===> 5 * (4 * (3 * fact(2)))
===> 5 * (4 * (3 * (2 * fact(1))))
===> 5 * (4 * (3 * (2 * 1)))
===> 5 * (4 * (3 * 2))
===> 5 * (4 * 6)
===> 5 * 24
===> 120

遞歸函數的優勢是定義簡單,邏輯清晰。理論上,全部的遞歸函數均可以寫成循環的方式,但循環的邏輯不如遞歸清晰。ip

使用遞歸函數須要注意防止棧溢出。在計算機中,函數調用是經過棧(stack)這種數據結構實現的,每當進入一個函數調用,棧就會加一層棧幀,每當函數返回,棧就會減一層棧幀。因爲棧的大小不是無限的,因此,遞歸調用的次數過多,會致使棧溢出。能夠試試計算 fact(10000)。it

任務

漢諾塔 (http://baike.baidu.com/view/191666.htm) 的移動也能夠看作是遞歸函數。io

咱們對柱子編號爲a, b, c,將全部圓盤從a移到c能夠描述爲:class

若是a只有一個圓盤,能夠直接移動到c;

若是a有N個圓盤,能夠當作a有1個圓盤(底盤) + (N-1)個圓盤,首先須要把 (N-1) 個圓盤移動到 b,而後,將 a的最後一個圓盤移動到c,再將b的(N-1)個圓盤移動到c。

請編寫一個函數,給定輸入 n, a, b, c,打印出移動的步驟:

move(n, a, b, c)

例如,輸入 move(2, 'A', 'B', 'C'),打印出:

A --> B
A --> C
B --> C

【分析】
移動第n個盤子是從a-->c,
在移動第n個盤子之前,是將n-1個盤子從a-->b, 此時b爲目標柱,c爲中轉柱
在移動第n個盤子以後,是將n-1個盤子從b-->c, 此時c爲目標柱,a爲中轉柱
答案:

函數 move(n, a, b, c) 的定義是將 n 個圓盤從 a 藉助 b 移動到 c。

參考代碼:

def move(n, a, b, c):
    if n ==1:
        print a, '-->', c
        return
    move(n-1, a, c, b)
    print a, '-->', c
    move(n-1, b, a, c)
move(4, 'A', 'B', 'C')
相關文章
相關標籤/搜索