python3.5.4 遞歸函數最噁心的時候莫非棧溢出(Stack overflow)。PS:另外很多人在學習Python的過程中,往往因為沒有好的教程或者沒人指導從而導致自己容易放棄,為此我建了個Python交流.裙 :一久武其而而流一思(數字的諧音)轉換下可以找到了,裡面有最新Python教程項 ...
python3.5.4
遞歸函數最噁心的時候莫非棧溢出(Stack overflow)。
PS:另外很多人在學習Python的過程中,往往因為沒有好的教程或者沒人指導從而導致自己容易放棄,為此我建了個Python交流.裙 :一久武其而而流一思(數字的諧音)轉換下可以找到了,裡面有最新Python教程項目可拿,不懂的問題多跟裡面的人交流,都會解決哦!
如何解決?
人為設置遞歸深度
使用python寫的遞歸程式如果遞歸太深, 那麼極有可能因為超過系統預設的遞歸深度限制而出現錯誤。一般預設遞歸長度在1000左右。
RuntimeError: maximum recursion depth exceeded in comparison
顯然此時我們可以人為修改
import sys
sys.setrecursionlimit(1000000) #括弧中的值為遞歸深度
尾遞歸優化
註:這隻是一種思維的科普
解決遞歸調用棧溢出的另一種方法是通過尾遞歸優化,事實上尾遞歸和迴圈的效果是一樣的,所以,把迴圈看成是一種特殊的尾遞歸函數也是可以的。
尾遞歸是指,在函數返回的時候,調用自身本身,並且,return語句不能包含表達式。這樣,編譯器或者解釋器就可以把尾遞歸做優化,使遞歸本身無論調用多少次,都只占用一個棧幀,不會出現棧溢出的情況。
上面的fact(n)函數由於return n * fact(n - 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)
可以看到,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
尾遞歸調用時,如果做了優化,棧不會增長,因此,無論多少次調用也不會導致棧溢出。
遺憾的是,大多數編程語言沒有針對尾遞歸做優化,Python解釋器也沒有做優化,所以,即使把上面的fact(n)函數改成尾遞歸方式,也會導致棧溢出。
Python標準的解釋器沒有針對尾遞歸做優化,任何遞歸函數都存在棧溢出的問題
小結
方法一:人為修改預設遞歸長度
方法二:人為修改python解釋器,將其優化,會十分有趣
———PS:另外很多人在學習Python的過程中,往往因為沒有好的教程或者沒人指導從而導致自己容易放棄,為此我建了個Python交流.裙 :一久武其而而流一思(數字的諧音)轉換下可以找到了,裡面有最新Python教程項目可拿,不懂的問題多跟裡面的人交流,都會解決哦!
本文的文字及圖片來源於網路加上自己的想法,僅供學習、交流使用,不具有任何商業用途,版權歸原作者所有,如有問題請及時聯繫我們以作處理。