1. 程式人生 > >【算法】遞歸

【算法】遞歸

創建 容易 text tac 否則 else 階乘 所有 壓入

遞歸

實例:在盒子中尋找鑰匙

方法1:使用while循環

算法

(1) 創建一個要查找的盒子堆。

(2) 從盒子堆取出一個盒子,在裏面找。

(3) 如果找到的是盒子,就將其加入盒子堆中,以便以後再查找。

(4) 如果找到鑰匙,則大功告成!

(5) 回到第二步。

代碼
def look_for_key(main_box):
    pile=main_box.make_a_pile_to_look_through()
    while pile is not empty:
        box=pile.grap_a_box
        for item in box:
            if item.is_a_box():
                pile.append(item)
            elif item.is_a_key():
                print(‘found a key‘)

  

方法2:使用遞歸

算法

(1) 檢查盒子中的每樣東西。

(2) 如果是盒子,就回到第一步。

(3) 如果是鑰匙,就大功告成!

代碼
def look_for_key(box):
    for item in box:
        if item.is_a_box():
            look_for_key(item)  #遞歸
        elif item.is_a_key():
            print(‘found a key‘)

  

如果使用循環,程序的性能可能更高;如果使用遞歸,程序可能更容易理解。如何選擇要看什麽對你來說更重要。

基線條件和遞歸條件

編寫遞歸函數時,必須告訴它何時停止遞歸。否則會導致無限循環。

遞歸函數兩部分

基線條件(base case)和遞歸條件(recursive case)

遞歸條件:指的是函數調用自己
基線條件:指的是函數不再調用自己,從而避免形成無限循環。

示例
def countdown(i):
    print(i)
    if i<=0:                       #基線條件
       return 
    else:                          #遞歸條件
        countdown(i-1)
 
print(countdown(4))

  

定義

棧(stack)又名堆棧,它是一種運算受限的線性表。其限制是僅允許在表的一端進行插入和刪除運算。

特點

LIFO,即後進先出(Last in, first out)

調用棧(call stack)

計算機在內部使用被稱為調用棧的棧。

示例
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()

print(greet(‘lilip‘))

  

調用過程

  1. 調用greet(‘lilip’),首先為該函數調用分配一塊內存
  2. 打印,hello,lilip!
  3. 調用greet2(‘lilip’),接著為這個函數調用分配一塊內存
  4. 計算機使用一個棧表示這些內存塊,其中第二個內存塊位於第一個內存塊的上面。
  5. 打印,how are you,lilip?greet2函數運行完畢,然後從函數調用返回。此時,棧頂的內存塊被彈出。
  6. 棧頂內存塊是函數greet,返回到函數greet。
  7. 打印getting ready to say bye..
  8. 調用bye()函數,棧頂添加函數bye的內存塊
  9. 打印,ok bye!並從這個函數返回。
  10. 返回到函數greet,此時運行完畢。從函數greet返回,

調用另一個函數時,當前函數暫停並處於未完成狀態。該函數的所有變量的值都還在內存中

這個棧用於存儲多個函數的變量,被稱為調用棧。

遞歸調用棧

遞歸函數也使用調用棧!

示例

階乘遞歸函數

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

  

調用過程

代碼

調用棧

備註

fact(3)

fact

x

3

第一次調用fact

x=3

if x==1:

fact

x

3

else:

fact

x

3

return x*fact(x-1)

fact

x

2

fact

x

3

遞歸調用

if x==1:

fact

x

2

fact

x

3

現在位於對fact的第二次調用中

x=2

最上面的函數調用是當前所處的調用

else:

fact

x

2

fact

x

3

兩個函數調用都有變量x,但這些x變量的值不同

return x*fact(x-1)

fact

x

1

fact

x

2

fact

x

3

在棧頂層調用中,不能訪問下面其他內存塊調用的x變量,反之亦然

if x==1:

fact

x

1

fact

x

2

fact

x

3

return 1

fact

x

1

fact

x

2

fact

x

3

從棧中彈出第一個方塊,意味著將從這個調用返回,返回1

return x*fact(x-1)

fact

x

2

fact

x

3

x為2

fact(x-1)返回1

最終返回2

return x*fact(x-1)

fact

x

3

x為3

fact(x-1)返回2

最終返回6

註意:

  1. 每個fact調用都有自己的x變量。在一個函數調用中不能訪問另一個的x變量。
  2. 每個函數調用都要占用一定的內存,如果棧很高,就意味著計算機存儲了大量函數調用的信息。

小結

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

【算法】遞歸