1. 程式人生 > >《笨辦法學Python》(13)---函式概念:迴圈VS遞迴,尾遞迴

《笨辦法學Python》(13)---函式概念:迴圈VS遞迴,尾遞迴

參考文件

http://www.cnblogs.com/liunnis/articles/4604967.html

https://blog.csdn.net/tianpingxian/article/details/80821504

https://blog.csdn.net/tcy23456/article/details/84111639   #py不支援尾遞迴

 

 

迴圈與遞迴(階乘的例子)

 

迴圈 cycle  cyclic

列印中間過程的迴圈

>>> def funcA2(n):
    fact=1
    for i in range(n):
        fact=fact*(i+1)
        print(i+1,"'s fact is",fact) #這個可以不要
    return fact

>>> funcA2(5)
1 's fact is 1
2 's fact is 2
3 's fact is 6
4 's fact is 24
5 's fact is 120
120
>>> 

簡寫迴圈

>>> def funcCycle(n):
    fact=1
    for i in range(1,n+1,1):
        fact*=i
    return fact

>>> funcCycle(5)
120

 

遞迴 recursion

什麼叫遞迴?如果一個函式在內部呼叫自己,就被稱為遞迴

(1)遞迴理論上全部都可以寫成遞迴?

(2)遞迴寫起來看起來比迴圈要簡單,邏輯更清晰

>>> def funcA1(n):
    if n ==1:
        return 1
    return n*funcA1(n-1)

>>> funcA1(5)
120

定義階乘factorial lambda表示式;遞迴實現

 

>>> funcAA1=(lambda n:1 if n==1 else n*funcAA1(n-1))
>>> funcAA1(5)
120

 

 

遞迴的問題:

(1) 這種遞迴,是反覆呼叫自己,直到條件滿足(和while相反邏輯)

(2)但是因為反覆呼叫,會導致在最後1次計算,計算壓力大

(3)使用遞迴函式需要注意防止棧溢位。

函式呼叫是通過棧(stack)這種資料結構實現的,每當進入一個函式呼叫,棧就會加一層棧幀,每當函式返回,棧就會減一層棧幀。由於棧的大小不是無限的,所以,遞迴呼叫的次數過多,會導致棧溢位。

(4)不能用在生成器函式和協程中??

>>> import sys
>>> sys.getrecursionlimit()
1000

可以試試fact(1000):會報錯  maximum recursion depth exceeded

 

​stack的堆積

5*4*3*2*funcA1(1)

5*4*3*funcA1(2)

5*4*funcA1(3)

5×funcA1(4)

 

 

 

 

尾遞迴 tail_recursion

尾遞迴是指,在函式返回的時候,呼叫自身本身,並且,return語句不能包含表示式。

(1)解決遞迴呼叫棧溢位的方法是通過尾遞迴優化

         事實上尾遞迴和迴圈的效果是一樣的,把迴圈看成是一種特殊的尾遞迴函式也是可以的。

(2) 每次遞迴都計算了一次,沒放到最後計算,壓力也小

(3)尾遞迴本身無論呼叫多少次,都只佔用一個棧幀,不會出現棧溢位的情況。

>>> def funcRecursion1(n,product=1):
    if n==1:
        return product
    return funcRecursion1(n-1,n*product)

>>> funcRecursion1(5,1)
120
>>> funcRecursion1(3,1)
6
>>>