以上面一個公式為例:
import numpy as np def getPi(n): if n == 0: return np.power(-1,n)*(1.0/(2*n+1)) else: return np.power(-1,n)*(1.0/(2*n+1))+getPi(n-1) print 4*getPi(100)
可以通過上面一個遞歸實現。
特點:
①遞歸就是在過程或者函數里調用自身。
②在使用遞歸策略時,必須有一個明確的遞歸條件,稱為遞歸出口。
③遞歸算法解題通常顯得很簡潔,但遞歸算法解題的效率較低。所以一般不倡導使用遞歸算法設計程序。
④在遞歸調用的過程當中系統的每一層的返回點、局部變量等開辟了棧來存儲。遞歸函數次數過多容易造成棧溢出等。
所以一般不倡導用遞歸算法設計程序。
要求:
遞歸算法所體現的"重復"一般有三個條件:
①每次在調用規模上都有所縮小(通常是減半)。
②相鄰兩次重復之間有緊密的聯系,前一次要為后一次做准備(通常前一次的輸出就作為后一次的輸入)。
③在問題的規模極小時必須用直接接觸解答而不再進行遞歸調用,因而每次遞歸調用都是有條件的(以規模未達到直接解答的大小為條件),
無條件的遞歸調用將會成為死循環而不能正常結束。
每當你調用一個函數,在這個函數執行前都會將之前的代碼地址(也就是調用點)入棧,等被調用的函數執行完將地址出棧,程序根據這個數據返回調用點。
若遞歸調用次數太多,就會只入棧不出棧,於是堆棧就被壓爆了,此為棧溢出。
python中的解決辦法:
1、人為設置遞歸深度
import sys sys.setrecursionlimit(1000000) #括號中的值為遞歸深度
事實上並不能完全解決,太多還是會程序崩潰的。
2、所謂的尾遞歸
import numpy as np def getPi(n,m): if n == 0: return m+np.power(-1,n)*(1.0/(2*n+1)) else: return getPi(n-1,m+np.power(-1,n)*(1.0/(2*n+1))) print 4*getPi(100,0)
尾遞歸參考:https://www.cnblogs.com/hello--the-world/archive/2012/07/19/2599003.html
尾遞歸的寫法就是將操作的值作為參數傳遞,事實上,python並不支持尾遞歸的優化!而且對遞歸的次數有限制,當遞歸深度超過1000時,會拋出異常。
故對於繼續研究突破遞歸次數的話,雖然有高手找到解決辦法,並沒有太大意義。
3、利用迭代的方式,而不是使用遞歸(譬如,reduce)
import numpy as np s = reduce(lambda x,n:x+np.power(-1,n)*(1.0/(2*n+1)),[np.power(-1,0)*(1.0/(2*0+1))]+range(1,100000)) print 4*s s = reduce(lambda x,n:x+np.power(-1,n)*(1.0/(2*n+1)) if x>0 else np.power(-1,x)*(1.0/(2*x+1))+np.power(-1,n)*(1.0/(2*n+1)),\ range(0,100000)) print 4*s
可以看到,利用reduce函數是處理這類問題的比較好的辦法。用一句話總結:
普通程序員用迭代,天才程序員用遞歸!