如果一個函數在內部調用自己,那么這個函數就是遞歸函數。
例如一個階乘函數:fact(n)=n! ,其實可以寫成 fact(n)=n x fact(n-1)。
fact(n) 以遞歸的方式可以表示為:
def fact(n):
if n==1:
return 1
return n*fact(n-1)
遞歸函數容易引起棧溢出。在計算機中,函數調用是通過堆棧實現的。每進入一個函數調用,堆棧會增加一層棧幀;每次函數返回,棧幀會減少一層。由於堆棧大小不是無限的,所以遞歸調用次數過多會導致棧溢出。可以試試 fact(1000)。
此問題可以通過尾遞歸優化。
尾遞歸是指,在函數返回時,調用函數自身,並且return語句不包含表達式。這樣編譯器就可以把尾遞歸做優化,使遞歸本身無論調用多少次,都只占用一個棧幀。
事實上,尾遞歸和循環的效果是一樣的,所以可以把循環堪稱是一種特殊的尾遞歸函數。
上面的函數修改如下:
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)
此時,return僅返回遞歸函數本身,num-1和num*product在函數調用前就會被計算,不影響函數調用。