尾遞歸python
A. python的尾遞歸
原因很多人的都知道,讓我們先回顧一下函數調用的大概過程:
1)調用開始前,調用方(或函數本身)會往棧上壓相關的數據,參數,返回地址,局部變數等。
2)執行函數。
3)清理棧上相關的數據,返回。
因此,在函數 A 執行的時候,如果在第二步中,它又調用了另一個函數 B,B 又調用 C.... 棧就會不斷地增長不斷地裝入數據,當這個調用鏈很深的時候,棧很容易就滿 了,這就是一般遞歸函數所容易面臨的大問題。
而尾遞歸在某些語言的實現上,能避免枯春上述所說的問題,注意是某些語言上,尾遞歸本身並不能蠢敗擾消除函數調用棧過長的問題,那什麼是尾遞歸呢?在上面寫的一般遞歸函數 func() 中,我們可以看到,func(n) 是依賴於 func(n-1) 的,func(n) 只有在得到 func(n-1) 的結果之後,才能帶旦計算它自己的返回值,因此理論上,在 func(n-1) 返回之前,func(n),不能結束返回。因此func(n)就必須保留它在棧上的數據,直到func(n-1)先返回,而尾遞歸的實現則可以在編譯器的幫助下,消除這個限制
B. 如何看待以及理解Python的這種尾遞歸優化
TCO,tail-call optimization,其實有多種解讀方式。
最常見的解讀方式是:對於尾調用的函數調用,不要浪費棧空間,而要復用調用者的棧空間。這樣的結果就是一長串尾調用不會爆棧,而沒有TCO的話同樣的調用就會爆棧。
從這個意義上說,題主貼的那個recipe確實達到了TCO的部分目的:
通過stack introspection查看調用鏈上的調用者之中有沒有自己
有的話,通過拋異常來迫使棧回退(stack unwind)到之前的一個自己的frame
在回退到的frame接住異常,拿出後來調用的參數,用新參數再次調用自己
這樣就可以讓尾遞歸不爆棧。但這樣做性能是沒保證的…而且對於完全沒遞歸過的一般尾調用也不起作用。
一種對TCO的常見誤解是:由編雀寬譯器或運行時系統把尾調用/尾遞歸實現得很快。這不是TCO真正要強調的事情——不爆棧慧譽才是最重要的。也就是說其實重點不在「優化」,而在於「頃碧亮尾調用不爆棧」這個語義保證。
「proper tail-call」的叫法遠比「tail-call optimization」來得合適。
因而像題主說的那種做法,可以算部分TCO,但算不上「性能優化」意義上的優化。
C. scheme遞歸的優勢在哪
python根祥燃本就沒有尾遞歸,scheme卻有,所以scheme更有效率
尾遞歸的優勢,是可以迭代,程序消耗的內液棚存基本是恆定的
據我所知,尾遞歸不是大部分語言擁有的特性,C語言和lisp都謹埋虛用,連C++都沒有,遑論其他語言了
chezscheme有很多優化選項,沒開的話哪有優勢?
尾遞歸,就是scheme相比python的一個絕對優勢
D. python為什麼不支持尾遞歸
Python本身是不支持尾遞歸的(via),並且對遞歸次數有限制的,當遞歸次數超過1000次的時候,就會冊此芹拋州畢出「RuntimeError: maximum recursion depth exceeded」異常扒帶。
E. 關於python遞歸函數怎樣理解
遞歸的思想主要是能夠重復某些動作,比如簡單的階乘,次方,回溯中的八皇後,數獨,還有漢諾塔,分形。
由於堆棧的機制,一般的遞歸可以保留某些變數在歷史狀態中,比如你提到的return
x
*
power...,
但是某些或許龐大的問題或者是深度過大的問題就需要盡量避免遞歸,因為可能會棧溢出。還有一個問題是~python不支持尾遞歸優化!!!!所以~還是盡量避免遞歸的出現。
def
power(x,
n)
if
n
<
0:
return
1
return
x
*
power(x,
n
-
1)
power(3,
3)
3
*
power(3,
2)
3
*
(3
*
power(3,
1))
3
*
(3
*
(3
*
power(3,
0)))
3
*
(3
*
(3
*
1))
這里n
=
0,
return
1
3
*
(3
*
3)
3
*
9
27
當函數形參n=0的時候,開始回退~直到第一次調用power結束。
F. 如何理解python中的遞歸函數
遞歸式方法可以被用於解決很多的計算機科學問題,因此它是計算機科學中十分重要的一個概念。
絕大多數編程語言支持函數的自調用,在這些語言中函數可以通過調用自身來進行遞歸。計算理論可以證明遞歸的作用可以完全取代循環,因此在很多函數編程語言(如Scheme)中習慣用遞歸來實現循環。
計算機科學家尼克勞斯·維爾特如此描述遞歸:
遞歸的強大之處在於它允許用戶用有限的語句描述無限的對象。因此,在計算機科學中,遞歸可以被用來描述無限步的運算,盡管描述運算的程序是有限的。
python 2 遞歸函數和其它語言,基本沒有差別,只是不支持尾遞歸。無限遞歸最大值為固定的,但可以修改。
作者:黃哥
G. python,怎麼使用遞歸的方法,提取括弧中的字串符
當遞歸調用是整個函數體中滾伏中最後執行的語句且它的返回值不屬於表達式的一部分時,這個遞歸調用就是尾遞歸。
尾遞歸函數的特點是在回歸過程中不用做任何賣攜操作,這個特性很重要,備豎因為大多數現代的編譯器會利用這種特點自動生成優化的代碼。
H. 如何看待以及理解Python的這種尾遞歸優化
把需要優化的函數的return改成yield,外面套個裝辯喚飾器,就叫tail_call_opm。裝飾器最內層的邏輯是
while True:
try:
ret=next(ret)
except:
return ret
這個應該沒有復用釋放的空間…但刷題時換了這個就不爆棧了侍灶或。返回閉包的話情況應該會更復雜一些。
不失為一個快速簡單的辦法老伍。
I. 很奇怪,為什麼用Python的人喜歡遞歸呢
Python沒有尾遞歸鬧迅扮優化(按照常理應該沒有,否則我只能覺得我所在的並非人間),就連Common Lisp都不要求這種優化,盡管很多Common Lisp實現都做這種優化或者提供pragma選昌梁項來打開這種優化,於是造成好像液灶是個Lisp就要支持尾遞歸優化一樣。
J. 遞歸與偽遞歸區別,Python 實現遞歸與尾遞歸
(1)數據的定義是按遞歸定義的。(n的階乘)
(2)問題解法按遞歸實現。(回溯)
(3)數據的結構形式是按遞歸定義的。(二叉樹的遍歷,圖的搜索)