軟件環境:Python 3.7.0b4
一、基線條件和遞歸條件
由於遞歸函數調用自己,因此編寫這樣的函數時很容易出錯,進而導致無限循環。例如:
def countdown(i): print(i) countdown(i-1) countdown(5) # 測試數據
當我們編寫遞歸函數時,必須告訴它何時停止遞歸。所以,每個遞歸函數都有兩部分:
- 基線條件(base case):函數調用自己。
- 遞歸條件(recursice case):函數不再調用自己,從而避免無限循環。
def countdown(i): print(i) # 基線條件 if i <= 0: return # 遞歸條件 else: countdown(i-1) countdown(5) # 測試數據
二、調用棧
計算機在內部使用被稱為調用棧的棧。
def greet2(name): print("how are you, ", name, "?") def bye(): print("ok bye!") def greet(name): print("hello, ", name, "!") greet2(name) print("getting ready to say bye...") bye() greet("adit")
調用過程如下:
- 假設調用greet("adit"),計算機將首先為該函數調用分配一塊內存;
- 在這個內存中,變量name被設置為adit,並存儲進這個內存中;
- 接下來,打印 hello,adit !,再調用greet2(name),此時的name=adit。同樣,計算機也會為這個greet2函數調用分配一塊內存;
- 計算機使用一個棧來表示這些內存塊,其中第二個內存塊位於第一個內存塊上面。當打印 how are you,adit?,然后從函數調用返回,棧頂的內存塊被彈出;
- 現在棧頂的內存塊是函數greet,這意味剛才執行完greet2函數后返回到了函數greet里,因此當調用函數greet2時,函數greet只執行了一部分。所以我們要記住一個重要的概念:調用另一個函數時,當前函數暫停並處於未完成狀態。
- 該函數的所有變量的值都還在內存中,執行完函數greet2后,返回到函數greet中,並從離開的地方開始繼續往下執行打印 getting ready to say bye...,再調用函數bye。
- 在棧頂添加函數bye的內存塊,然后 打印 ok bye !,並從這個函數返回。
- 現在再次回到了函數greet,由於沒有往下執行的操作,所以直接從函數greet返回。這個棧用於存儲多個函數的變量,被稱為調用棧。
3.1:可獲得的信息有
- 調用了函數greet,並將參數name的值指定為maggle;
- 函數greet調用了函數greet2,並將參數name的值指定為maggle;
- 此時函數greet處於未完成狀態;
- 當前調用的函數為greet2;
- 這個函數執行完畢后,函數greet將接着執行。
三、遞歸調用棧
def fact(x): if x == 1: return 1 else: return x * fact(x-1)
使用棧的方式表述如下:
3.1:棧將不斷地擴大。因為每個程序可使用的調用棧空間有限,程序用完這些空間后,將因棧的溢出而終止。
四、小結
- 遞歸指的是調用自己的函數。
- 每個遞歸函數都有兩個條件:基線條件和遞歸條件。
- 棧有兩種操作:壓入和彈出。
- 所有函數調用都進入調用棧。
- 調用棧可能非常長,所以講占用計算機大量的內存。