題目:
計算階乘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)已經可以正常輸出了。