《圖解算法》——遞歸

1.遞歸

假設(shè)你在祖母(老外都喜歡舉祖母的例子)的閣樓中翻箱倒柜肥荔,發(fā)現(xiàn)了一個上鎖的神秘手提箱。


祖母告訴你朝群,鑰匙很可能在下面這個盒子里燕耿。

這個盒子里有盒子,而盒子里的盒子又有盒子姜胖。鑰匙就在某個盒子中誉帅。為找到鑰匙,你將使用什么算法右莱?

以下是一種方法:

(1) 創(chuàng)建一個要查找的盒子堆蚜锨。

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

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

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

(5) 回到第二步耘柱。

下面是另一種方法圆雁。

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

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

(3) 如果是鑰匙轴咱,就大功告成汛蝙!

在你看來烈涮,哪種方法更容易呢?

我們從直觀上來看窖剑,第二種的步驟相對來說比較少坚洽。

第一種是while循環(huán),只要盒子堆不空西土,就從中取一個盒子讶舰,并仔細查找。

第二種是遞歸需了,自己調(diào)自己跳昼,偽代碼如下:

遞歸只是讓解決方案更清晰,并沒有性能上的優(yōu)勢肋乍。實際上鹅颊,在有些情況下,使用循環(huán)的性能更好墓造。

2.基線條件和遞歸條件

由于遞歸函數(shù)調(diào)用自己堪伍,因此編寫這樣的函數(shù)時很容易出錯,進而導致無限循環(huán)觅闽。例如帝雇,假設(shè)你要編寫一個像下面這樣倒計時的函數(shù)。

def countdown(i):

? ? ? ? ? ? print i

? ? ? ? ? ? countdown(i-1)

如果你運行上述代碼蛉拙,將發(fā)現(xiàn)一個問題:這個函數(shù)運行起來沒完沒了尸闸!

編寫遞歸函數(shù)時,必須告訴它何時停止遞歸刘离。正因為如此室叉,每個遞歸函數(shù)都有兩部分:基線條件(base case)和遞歸條件(recursive case)。遞歸條件指的是函數(shù)調(diào)用自己硫惕,而基線條件則指的是函數(shù)不再調(diào)用自己茧痕,從而避免形成無限循環(huán)。

我們來給函數(shù)countdown添加基線條件恼除。


現(xiàn)在踪旷,這個函數(shù)將像預(yù)期的那樣運行,如下所示豁辉。

3.棧

調(diào)用棧不僅對編程來說很重要令野,使用遞歸時也必須理解這個概念。

有一個待辦清單的例子徽级,你可將待辦事項添加到該清單的任何地方气破,還可刪除任何一個待辦事項。一疊便條要簡單得多:插入的待辦事項放在清單的最前面餐抢;讀取待辦事項時现使,你只讀取最上面的那個低匙,并將其刪除。因此這個待辦事項清單只有兩種操作:壓入(插入)和彈出(刪除并讀忍夹狻)顽冶。

3.1調(diào)用棧

計算機在內(nèi)部使用被稱為調(diào)用棧的棧。我們來看看計算機是如何使用調(diào)用棧的售碳。下面是一個簡單的函數(shù)强重。

? ? ? ? def greet(name):

? ? ? ? ? ? print "hello, " + name + "! "

? ? ? ? ? ? greet2(name)

? ? ? ? ? ? print "getting ready to say bye..."

? ? ? ? ? ? bye()

這個函數(shù)問候用戶,再調(diào)用另外兩個函數(shù)贸人。這兩個函數(shù)的代碼如下间景。

? ? ? ? def greet2(name):

? ? ? ? ? ? print "how are you, " + name + "? "

? ? ? ? def bye():

? ? ? ? ? ? print "ok bye! "

假設(shè)你調(diào)用greet("maggie"),計算機將首先為該函數(shù)調(diào)用分配一塊內(nèi)存灸姊。


我們來使用這些內(nèi)存拱燃。變量name被設(shè)置為maggie,這需要存儲到內(nèi)存中力惯。


每當你調(diào)用函數(shù)時碗誉,計算機都像這樣將函數(shù)調(diào)用涉及的所有變量的值存儲到內(nèi)存中。接下來父晶,你打印hello, maggie!哮缺,再調(diào)用greet2("maggie")。同樣甲喝,計算機也為這個函數(shù)調(diào)用分配一塊內(nèi)存尝苇。


計算機使用一個棧來表示這些內(nèi)存塊,其中第二個內(nèi)存塊位于第一個內(nèi)存塊上面埠胖。你打印how are you, maggie?糠溜,然后從函數(shù)調(diào)用返回。此時直撤,棧頂?shù)膬?nèi)存塊被彈出非竿。


現(xiàn)在,棧頂?shù)膬?nèi)存塊是函數(shù)greet的谋竖,這意味著你返回到了函數(shù)greet红柱。當你調(diào)用函數(shù)greet2時,函數(shù)greet只執(zhí)行了一部分蓖乘。這是本節(jié)的一個重要概念:調(diào)用另一個函數(shù)時锤悄,當前函數(shù)暫停并處于未完成狀態(tài)。該函數(shù)的所有變量的值都還在內(nèi)存中嘉抒。執(zhí)行完函數(shù)greet2后零聚,你回到函數(shù)greet,并從離開的地方開始接著往下執(zhí)行:首先打印getting ready to say bye…,再調(diào)用函數(shù)bye隶症。


在棧頂添加了函數(shù)bye的內(nèi)存塊容诬。然后,你打印ok bye!沿腰,并從這個函數(shù)返回。


現(xiàn)在你又回到了函數(shù)greet狈定。由于沒有別的事情要做颂龙,你就從函數(shù)greet返回。這個棧用于存儲多個函數(shù)的變量纽什,被稱為調(diào)用棧措嵌。

3.2 遞歸調(diào)用棧

遞歸函數(shù)也使用調(diào)用棧,我們以階乘函數(shù)為例

下面來詳細分析調(diào)用fact(3)時調(diào)用棧是如何變化的芦缰。棧頂?shù)姆娇蛑赋隽水斍皥?zhí)行到了什么地方企巢。

注意,每個fact都有自己的x變量让蕾,在一個函數(shù)的調(diào)用中不能訪問另一個x變量浪规。

使用棧雖然很方便,但是也要付出代價:存儲詳盡的信息可能占用大量的內(nèi)存探孝。每個函數(shù)調(diào)用都要占用一定的內(nèi)存笋婿,如果棧很高,就意味著計算機存儲了大量函數(shù)3調(diào)用的信息顿颅。在這種情況下缸濒,你有兩種選擇。

? 重新編寫代碼粱腻,轉(zhuǎn)而使用循環(huán)庇配。

? 使用尾遞歸。這是一個高級遞歸

4. 小結(jié)

? 遞歸指的是調(diào)用自己的函數(shù)绍些。

? 每個遞歸函數(shù)都有兩個條件:基線條件和遞歸條件捞慌。

? 棧有兩種操作:壓入和彈出。

? 所有函數(shù)調(diào)用都進入調(diào)用棧遇革。

? 調(diào)用椙淠郑可能很長,這將占用大量的內(nèi)存萝快。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末锻霎,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子揪漩,更是在濱河造成了極大的恐慌旋恼,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,816評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件奄容,死亡現(xiàn)場離奇詭異冰更,居然都是意外死亡产徊,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評論 3 385
  • 文/潘曉璐 我一進店門蜀细,熙熙樓的掌柜王于貴愁眉苦臉地迎上來舟铜,“玉大人,你說我怎么就攤上這事奠衔∽慌伲” “怎么了?”我有些...
    開封第一講書人閱讀 158,300評論 0 348
  • 文/不壞的土叔 我叫張陵归斤,是天一觀的道長痊夭。 經(jīng)常有香客問我,道長脏里,這世上最難降的妖魔是什么抄淑? 我笑而不...
    開封第一講書人閱讀 56,780評論 1 285
  • 正文 為了忘掉前任缰盏,我火速辦了婚禮滑凉,結(jié)果婚禮上吨凑,老公的妹妹穿的比我還像新娘。我一直安慰自己员淫,他們只是感情好合蔽,可當我...
    茶點故事閱讀 65,890評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著介返,像睡著了一般拴事。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上圣蝎,一...
    開封第一講書人閱讀 50,084評論 1 291
  • 那天刃宵,我揣著相機與錄音,去河邊找鬼徘公。 笑死牲证,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的关面。 我是一名探鬼主播坦袍,決...
    沈念sama閱讀 39,151評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼等太!你這毒婦竟也來了捂齐?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,912評論 0 268
  • 序言:老撾萬榮一對情侶失蹤缩抡,失蹤者是張志新(化名)和其女友劉穎奠宜,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,355評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡压真,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,666評論 2 327
  • 正文 我和宋清朗相戀三年娩嚼,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片滴肿。...
    茶點故事閱讀 38,809評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡岳悟,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出泼差,到底是詐尸還是另有隱情竿音,我是刑警寧澤,帶...
    沈念sama閱讀 34,504評論 4 334
  • 正文 年R本政府宣布拴驮,位于F島的核電站,受9級特大地震影響柴信,放射性物質(zhì)發(fā)生泄漏套啤。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,150評論 3 317
  • 文/蒙蒙 一随常、第九天 我趴在偏房一處隱蔽的房頂上張望潜沦。 院中可真熱鬧,春花似錦绪氛、人聲如沸唆鸡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽争占。三九已至,卻和暖如春序目,著一層夾襖步出監(jiān)牢的瞬間臂痕,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評論 1 267
  • 我被黑心中介騙來泰國打工猿涨, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留握童,地道東北人。 一個月前我還...
    沈念sama閱讀 46,628評論 2 362
  • 正文 我出身青樓叛赚,卻偏偏與公主長得像澡绩,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子俺附,可洞房花燭夜當晚...
    茶點故事閱讀 43,724評論 2 351

推薦閱讀更多精彩內(nèi)容

  • 遞歸的基本概念網(wǎng)上一大堆肥卡,這里說一下個人認為重要的點。 (3.1)基本條件和遞歸條件 編寫遞歸函數(shù)時昙读,必須告訴它何...
    書寫不簡單閱讀 946評論 0 6
  • 遞歸是很多算法都使用的一種編程方法召调。聽說遞歸是一種十分優(yōu)雅的問題解決辦法,可是對于初涉遞歸的我,還沒有形成這種獨特...
    愛吃西瓜的番茄醬閱讀 1,162評論 0 5
  • 遞歸 什么是遞歸 ? 在有基線條件的情況下迭代自身唠叛,即是在有結(jié)束條件的情況下函數(shù)不斷調(diào)用自己只嚣。如果沒有結(jié)束條件...
    仲冬初七閱讀 569評論 0 0
  • 計算機科學的新學生通常難以理解遞歸程序設(shè)計的概念册舞。遞歸思想之所以困難,原因在于它非常像是循環(huán)推理(circular...
    啟明_b56f閱讀 7,340評論 0 20
  • 最近在看《算法圖解》這本書障般,目前也在復(fù)習這些基礎(chǔ)的算法知識调鲸,正好也可以在這里做一些總結(jié),以加深自己的體會與理解挽荡。 ...
    hiric閱讀 3,840評論 0 0