函數遞歸

若是一個函數在內部調用自身自己,則該函數就是遞歸函數

遞歸優缺點
  優勢:使用遞歸函數的優勢是邏輯簡單清晰
     理論上,全部的遞歸函數均可以寫成循環的方式,但循環的邏輯不如遞歸清晰
  缺點:過深的調用會致使棧溢出

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

尾遞歸
  解決遞歸調用棧溢出的方法是經過尾遞歸優化
  事實上尾遞歸和循環的效果是同樣的,因此,把循環當作是一種特殊的尾遞歸函數也是能夠的編程

  尾遞歸是指,在函數返回的時候,調用自身自己,而且return語句不能包含表達式
  例如,def fun(n) : retrun n*fun(n-1), 則fun(n)只能等fun(n-1)結束才能夠,這樣一環套一環就會爆棧
  在尾遞歸調用時,編譯器或者解釋器就能夠把尾遞歸作優化,使遞歸自己不管調用多少次,都只佔用一個棧幀,不會出現棧溢出的狀況
  大多數編程語言沒有針對尾遞歸作優化,Python解釋器也沒有作優化,因此,即便把函數改爲尾遞歸方式,也會致使棧溢出
  也就是說尾遞歸須要解釋器提供幫助,單純從代碼上是沒法完全實現的數據結構

 

針對尾遞歸優化的語言能夠經過尾遞歸防止棧溢出。尾遞歸事實上和循環是等價的,沒有循環語句的編程語言只能經過尾遞歸實現循環
Python標準的解釋器沒有針對尾遞歸作優化,任何遞歸函數都存在棧溢出的問題編程語言

使用示例:函數

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 fact_iter(num - 1, num * product)僅返回遞歸函數自己,num - 1和num * product在函數調用前就會被計算,不影響函數調用
#fact(5)對應的fact_iter(5, 1)的調用以下:
===> fact_iter(5, 1)
===> fact_iter(4, 5)
===> fact_iter(3, 20)
===> fact_iter(2, 60)
===> fact_iter(1, 120)
===> 120
相關文章
相關標籤/搜索