日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

小白的算法初识课堂(part3)--递归

發布時間:2023/12/19 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 小白的算法初识课堂(part3)--递归 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

學習筆記
學習書目:《算法圖解》- Aditya Bhargava


文章目錄

      • 遞歸
      • 基線條件和遞歸條件
        • 調用棧
        • 遞歸調用棧



遞歸


首先,我們看一段代碼:

def print_num(my_list):for i in my_list:print(i)print_num([1, 3, 5, 7, 9])

輸出:

1 3 5 7 9

再看一段代碼:

def print_num2(my_list):if my_list:print(my_list.pop(0))print_num2(my_list)print_num2([1, 3, 5, 7, 9])

輸出:

1 3 5 7 9

我們看到的第一段代碼使用的是循環,第二段代碼使用的是遞歸,兩種方法結果相同。一般來說,遞歸能讓解決方案更清晰(雖然我舉的例子好像沒體現出來遞歸法更清晰),但并沒有性能上的優勢。實際上,在有些情況下,使用循環的性能更好。

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


基線條件和遞歸條件


由于遞歸函數調用自己,因此編寫這樣的函數時很容易出錯,進而導致無限循環。例如,假設我要編寫一個像下面這樣倒計時的函數:

def countdown(i): print(i) countdown(i-1)

如果我們運行上述代碼,將發現一個問題:這個函數運行起來沒完沒了!

編寫遞歸函數時,必須告訴它何時停止遞歸。正因為如此,每個遞歸函數都有兩部分:基線條件(base case)和遞歸條件(recursive case)。遞歸條件指的是函數調用自己,而基線條件則指的是函數不再調用自己,從而避免形成無限循環。

我們來給countdown函數添加一個基線條件:

def countdown(i): print(i)if i <= 1:returnelse:countdown(i-1)

現在,這個函數就會像預期那樣運行.



假設我們有一疊便條,這疊便條記錄著我們馬上要做的待辦事項,我們簡稱這疊便條為清單。當我們插入的待辦事項時,這個事件會放在清單的最上面;當我們讀取待辦事項時,也只讀取清單最上面的那個,且讀完就將其銷毀。因此這個清單只有兩種操作:壓入(插入)和彈出(刪除并讀取)。

這種數據結構被稱為棧。


調用棧


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

為了演示計算機是如何調用棧的,我們來看下面這個簡單的函數:

def greet(name):print(name, '!')greet2(name)print('too late!')bye()def greet2(name):print(name, '?')def bye():print('bye!')greet('maggie')

注意!print是一個函數,但是出于簡化考慮,我們假設它不是函數。


假設,我們調用greet('maggie'),計算機將首先為該函數調用分配一塊內存空間:


變量name被賦值為maggie,這需要存儲到內存中:


當我們調用函數時,計算機會將函數調用涉及的所有變量的值存儲到內存中。接下來,我們再調用greet2('maggie').同樣,計算機也為這個函數調用分配一塊內存。


計算機使用一個棧來表示這些內存塊,其中第二個內存塊位于第一個內存塊上面。我們打印maggie ?,然后從函數greet2的調用返回。此時,棧頂的內存塊被彈出。


現在,棧頂的內存塊是函數greet的,這意味著我們返回到了函數greet。當我調用函數greet2時,函數greet只執行了一部分。調用另一個函數時,當前函數暫停并處于未完成狀態,該函數的所有變量的值仍在內存中。

當執行完greet2函數后,我們繼續向下執行,首先打印too late!,再調用函數bye()。計算機在棧頂添加了函數bye的內存塊,然后我們打印bye!,并從該函數中返回。


現在,我們又回到了greet函數,由于無事可做,我們就從greet函數中返回。這個棧用于存儲多個函數的變量,故被稱為調用棧。


遞歸調用棧

遞歸函數也使用調用棧,我們來看看下面這個遞歸函數fact:

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

輸出:

6

下面我們來看一下調用fact(3)時,調用棧的變化:




每個fact調用都有自己的x變量,在一個函數調用中不能訪問另一個函數的x變量。

總結

以上是生活随笔為你收集整理的小白的算法初识课堂(part3)--递归的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。