python中的遞歸問題,求圓周率


以上面一個公式為例:

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函數是處理這類問題的比較好的辦法。用一句話總結:

                                                  普通程序員用迭代,天才程序員用遞歸!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM