Python遞歸函數如何寫?正確的Python遞歸函數用法!

在函數內部,能夠調用其餘函數。若是一個函數在內部調用自身自己,這個函數就是遞歸函數。
1、舉個例子,咱們來計算階乘n! = 1 x 2 x 3 x … x n,用函數fact(n)表示,能夠看出:
Python遞歸函數如何用怎麼操做
fact(n) = n! = 1 x 2 x 3 x … x (n-1) x n = (n-1)! x n = fact(n-1) x n
因此,fact(n)能夠表示爲n x fact(n-1),只有n=1時須要特殊處理。
ps:另外不少人在學習Python的過程當中,每每由於沒有好的教程或者沒人指導從而致使本身容易放棄,爲此我建了個Python交流.裙 :一久武其而而流一思(數字的諧音)轉換下能夠找到了,裏面有最新Python教程項目可拿,不懂的問題多跟裏面的人交流,都會解決哦!
因而,fact(n)用遞歸的方式寫出來就是:
def fact(n):
if n==1:
return 1
return n * fact(n - 1)
上面就是一個遞歸函數。能夠試試:編程

fact(1)
1網絡

fact(5)
120數據結構

fact(100)
93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
若是咱們計算fact(5),能夠根據函數定義看到計算過程以下:
===> fact(5)
===> 5 * fact(4)
===> 5 * (4 * fact(3))
===> 5 * (4 * (3 * fact(2)))
===> 5 * (4 * (3 * (2 * fact(1))))
===> 5 * (4 * (3 * (2 * 1)))
===> 5 * (4 * (3 * 2))
===> 5 * (4 * 6)
===> 5 * 24
===> 120
2、遞歸函數的優勢是定義簡單,邏輯清晰。理論上,全部的遞歸函數均可以寫成循環的方式,但循環的邏輯不如遞歸清晰。
使用遞歸函數須要注意防止棧溢出。在計算機中,函數調用是經過棧(stack)這種數據結構實現的,每當進入一個函數調用,棧就會加一層棧幀,每當函數返回,棧就會減一層棧幀。因爲棧的大小不是無限的,因此,遞歸調用的次數過多,會致使棧溢出。能夠試試fact(1000):編程語言

fact(1000)
Traceback (most recent call last):
File 「」, line 1, in 
File 「」, line 4, in fact

File 「」, line 4, in fact
RuntimeError: maximum recursion depth exceeded in comparison
解決遞歸調用棧溢出的方法是經過尾遞歸優化,事實上尾遞歸和循環的效果是同樣的,因此,把循環當作是一種特殊的尾遞歸函數也是能夠的。
尾遞歸是指,在函數返回的時候,調用自身自己,而且,return語句不能包含表達式。這樣,編譯器或者解釋器就能夠把尾遞歸作優化,使遞歸自己不管調用多少次,都只佔用一個棧幀,不會出現棧溢出的狀況。
上面的fact(n)函數因爲return n * fact(n - 1)引入了乘法表達式,因此就不是尾遞歸了。要改爲尾遞歸方式,須要多一點代碼,主要是要把每一步的乘積傳入到遞歸函數中:
def fact(n):
return fact_iter(n, 1)函數

def fact_iter(num, product):
if num == 1:
return product
return fact_iter(num - 1, num * product)
能夠看到,return fact_iter(num - 1, num * product)僅返回遞歸函數自己,num - 1和num * product在函數調用前就會被計算,不影響函數調用。學習

fact(5)對應的fact_iter(5, 1)的調用以下:優化

===> fact_iter(5, 1)
===> fact_iter(4, 5)
===> fact_iter(3, 20)
===> fact_iter(2, 60)
===> fact_iter(1, 120)
===> 120
尾遞歸調用時,若是作了優化,棧不會增加,所以,不管多少次調用也不會致使棧溢出。code

遺憾的是,大多數編程語言沒有針對尾遞歸作優化,Python解釋器也沒有作優化,因此,即便把上面的fact(n)函數改爲尾遞歸方式,也會致使棧溢出。blog

小結
使用遞歸函數的優勢是邏輯簡單清晰,缺點是過深的調用會致使棧溢出。教程

針對尾遞歸優化的語言能夠經過尾遞歸防止棧溢出。尾遞歸事實上和循環是等價的,沒有循環語句的編程語言只能經過尾遞歸實現循環。

Python標準的解釋器沒有針對尾遞歸作優化,任何遞歸函數都存在棧溢出的問題。
Python遞歸函數如何使用怎麼操做
練習
漢諾塔的移動能夠用遞歸函數很是簡單地實現。

請編寫move(n, a, b, c)函數,它接收參數n,表示3個柱子A、B、C中第1個柱子A的盤子數量,而後打印出把全部盤子從A藉助B移動到C的方法,例如:

-- coding: utf-8 --

def move(n, a, b, c):

if n == 1:
    print(a, '-->', c)

期待輸出:

A --> C

A --> B

C --> B

A --> C

B --> A

B --> C

A --> C

move(3, ‘A’, ‘B’, ‘C’)
Run
以上就是本次分享,另外不少人在學習Python的過程當中,每每由於沒有好的教程或者沒人指導從而致使本身容易放棄,爲此我建了個Python交流.裙 :一久武其而而流一思(數字的諧音)轉換下能夠找到了,裏面有最新Python教程項目可拿,不懂的問題多跟裏面的人交流,都會解決哦!

本文的文字及圖片來源於網絡加上本身的想法,僅供學習、交流使用,不具備任何商業用途,版權歸原做者全部,若有問題請及時聯繫咱們以做處理。

相關文章
相關標籤/搜索