《笨辦法學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
>>>