1. 程式人生 > >python 遞迴函式 棧溢位

python 遞迴函式 棧溢位

題目:

計算階乘n!=n*(n-1)*(n-2)*…3*2*1

用遞迴函式來表示為:

def f(x):

   if x==1:

       return 1

   return x*f(x-1)

程式碼截圖執行結果

計算5的階乘5!,執行正確。

接著計算大一點的數1000!:

程式碼截圖執行結果執行結果

可以看到執行結果報錯了,這是因為出現了棧溢位。

在計算機中,函式呼叫是通過棧(stack)這種資料結構實現的,每當進入一個函式呼叫,棧就會加一層棧幀,每當函式返回,棧就會減一層棧幀。由於棧的大小不是無限的,所以,遞迴呼叫的次數過多,會導致棧溢位。

在計算1000!時,遞迴函式使得函式呼叫次數非常多,層級很深,返回卻很少,導致堆疊無法容納大量的呼叫返回地址,從而產生溢位。

解決思路是:

對return語句進行尾遞迴優化,也就是避免在return語句裡出現表示式(上文程式碼中的‘return x*f(x-1)就是一個乘法表達式’),這樣直譯器或編譯器就會自動把尾遞迴進行優化,使得無論遞迴多少次函式,都只佔用一個棧,從而避免溢位的產生(原理上)。

def fact(n):

    return fact_iter(n, 1)

def fact_iter(num, product):

    if num == 1:

        return product

    return fact_iter(num - 1, num * product)

print fact(5)

上文程式碼是做了尾遞迴優化的情形,可惜的是python並不支援尾遞迴優化,python遞迴的次數在1000以內不會產生溢位,1000以上就要考慮用迴圈來代替了。

可修改成:

def function(x):

    s = 1

    if x == 1:

        return 1

    if x>1:

        for i in range(1,x+1):

            s = s*i

         return s

    else:

        return 'No Answer!'

print function(5)

程式碼截圖執行結果

print function(1000)已經可以正常輸出了。