《算法圖解》第三章筆記與課后練習_遞歸


軟件環境: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")

 

 

調用過程如下:

  1. 假設調用greet("adit"),計算機將首先為該函數調用分配一塊內存;
  2. 在這個內存中,變量name被設置為adit,並存儲進這個內存中;
  3. 接下來,打印 hello,adit !,再調用greet2(name),此時的name=adit。同樣,計算機也會為這個greet2函數調用分配一塊內存;
  4. 計算機使用一個棧來表示這些內存塊,其中第二個內存塊位於第一個內存塊上面。當打印 how are you,adit?,然后從函數調用返回,棧頂的內存塊被彈出;
  5. 現在棧頂的內存塊是函數greet,這意味剛才執行完greet2函數后返回到了函數greet里,因此當調用函數greet2時,函數greet只執行了一部分。所以我們要記住一個重要的概念:調用另一個函數時,當前函數暫停並處於未完成狀態
  6. 該函數的所有變量的值都還在內存中,執行完函數greet2后,返回到函數greet中,並從離開的地方開始繼續往下執行打印 getting ready to say bye...,再調用函數bye。
  7. 在棧頂添加函數bye的內存塊,然后 打印 ok bye !,並從這個函數返回。
  8. 現在再次回到了函數greet,由於沒有往下執行的操作,所以直接從函數greet返回。這個棧用於存儲多個函數的變量,被稱為調用棧。

3.1:可獲得的信息有

  1. 調用了函數greet,並將參數name的值指定為maggle;
  2. 函數greet調用了函數greet2,並將參數name的值指定為maggle;
  3. 此時函數greet處於未完成狀態;
  4. 當前調用的函數為greet2;
  5. 這個函數執行完畢后,函數greet將接着執行。

 

三、遞歸調用棧

def fact(x):
  if x == 1:
    return 1
  else:
    return x * fact(x-1)

使用棧的方式表述如下:

  

3.1:棧將不斷地擴大。因為每個程序可使用的調用棧空間有限,程序用完這些空間后,將因棧的溢出而終止。

 

四、小結

  • 遞歸指的是調用自己的函數。
  • 每個遞歸函數都有兩個條件:基線條件和遞歸條件。
  • 棧有兩種操作:壓入和彈出。
  • 所有函數調用都進入調用棧。
  • 調用棧可能非常長,所以講占用計算機大量的內存。

 


免責聲明!

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



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