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)已經可以正常輸出了。