python遞歸

遞歸函數(shù)

在函數(shù)內(nèi)部匾浪,可以調(diào)用其他函數(shù)。如果一個(gè)函數(shù)在內(nèi)部調(diào)用自身本身粹淋,這個(gè)函數(shù)就是遞歸函數(shù)。

舉個(gè)例子虏肾,我們來計(jì)算階乘n! = 1 x 2 x 3 x ... x n廓啊,用函數(shù)fact(n)表示,可以看出:

fact(n) = n! = 1 x 2 x 3 x ... x (n-1) x n = (n-1)! x n = fact(n-1) x n

所以封豪,fact(n)可以表示為n x fact(n-1)谴轮,只有n=1時(shí)需要特殊處理。

于是吹埠,fact(n)用遞歸的方式寫出來就是:

deffact(n):ifn==1:return1returnn * fact(n -1)

上面就是一個(gè)遞歸函數(shù)第步。可以試試:

>>> fact(1)1>>> fact(5)120>>> fact(100)93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000L

如果我們計(jì)算fact(5)缘琅,可以根據(jù)函數(shù)定義看到計(jì)算過程如下:

===> fact(5)===>5* fact(4)===>5* (4* fact(3))===>5* (4* (3* fact(2)))===>5* (4* (3* (2* fact(1))))===>5* (4* (3* (2*1)))===>5* (4* (3*2))===>5* (4*6)===>5*24===>120

遞歸函數(shù)的優(yōu)點(diǎn)是定義簡(jiǎn)單团秽,邏輯清晰安皱。理論上励堡,所有的遞歸函數(shù)都可以寫成循環(huán)的方式妓布,但循環(huán)的邏輯不如遞歸清晰。

使用遞歸函數(shù)需要注意防止棧溢出呻纹。在計(jì)算機(jī)中堆生,函數(shù)調(diào)用是通過棧(stack)這種數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)的专缠,每當(dāng)進(jìn)入一個(gè)函數(shù)調(diào)用,棧就會(huì)加一層棧幀淑仆,每當(dāng)函數(shù)返回涝婉,棧就會(huì)減一層棧幀。由于棧的大小不是無限的蔗怠,所以墩弯,遞歸調(diào)用的次數(shù)過多,會(huì)導(dǎo)致棧溢出寞射∮婀ぃ可以試試fact(1000):

>>> fact(1000)Traceback (most recent call last):? File "", line 1, inFile "", line 4, in fact? ...? File "", line 4, in factRuntimeError: maximum recursion depth exceeded

解決遞歸調(diào)用棧溢出的方法是通過尾遞歸優(yōu)化,事實(shí)上尾遞歸和循環(huán)的效果是一樣的怠惶,所以涨缚,把循環(huán)看成是一種特殊的尾遞歸函數(shù)也是可以的轧粟。

尾遞歸是指策治,在函數(shù)返回的時(shí)候,調(diào)用自身本身兰吟,并且通惫,return語句不能包含表達(dá)式。這樣混蔼,編譯器或者解釋器就可以把尾遞歸做優(yōu)化履腋,使遞歸本身無論調(diào)用多少次,都只占用一個(gè)棧幀惭嚣,不會(huì)出現(xiàn)棧溢出的情況遵湖。

上面的fact(n)函數(shù)由于return n * fact(n - 1)引入了乘法表達(dá)式,所以就不是尾遞歸了晚吞。要改成尾遞歸方式延旧,需要多一點(diǎn)代碼,主要是要把每一步的乘積傳入到遞歸函數(shù)中:

deffact(n):returnfact_iter(n,1)deffact_iter(num, product):ifnum ==1:returnproductreturnfact_iter(num -1, num * product)

可以看到槽地,return fact_iter(num - 1, num * product)僅返回遞歸函數(shù)本身迁沫,num - 1和num * product在函數(shù)調(diào)用前就會(huì)被計(jì)算,不影響函數(shù)調(diào)用捌蚊。

fact(5)對(duì)應(yīng)的fact_iter(5, 1)的調(diào)用如下:

===> fact_iter(5,1)===> fact_iter(4,5)===> fact_iter(3,20)===> fact_iter(2,60)===> fact_iter(1,120)===>120

尾遞歸調(diào)用時(shí)集畅,如果做了優(yōu)化,棧不會(huì)增長(zhǎng)缅糟,因此挺智,無論多少次調(diào)用也不會(huì)導(dǎo)致棧溢出。

遺憾的是窗宦,大多數(shù)編程語言沒有針對(duì)尾遞歸做優(yōu)化赦颇,Python解釋器也沒有做優(yōu)化谣辞,所以,即使把上面的fact(n)函數(shù)改成尾遞歸方式沐扳,也會(huì)導(dǎo)致棧溢出泥从。

小結(jié)

使用遞歸函數(shù)的優(yōu)點(diǎn)是邏輯簡(jiǎn)單清晰,缺點(diǎn)是過深的調(diào)用會(huì)導(dǎo)致棧溢出沪摄。

針對(duì)尾遞歸優(yōu)化的語言可以通過尾遞歸防止棧溢出躯嫉。尾遞歸事實(shí)上和循環(huán)是等價(jià)的,沒有循環(huán)語句的編程語言只能通過尾遞歸實(shí)現(xiàn)循環(huán)杨拐。

Python標(biāo)準(zhǔn)的解釋器沒有針對(duì)尾遞歸做優(yōu)化祈餐,任何遞歸函數(shù)都存在棧溢出的問題。

原文鏈接:https://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/00137473836826348026db722d9435483fa38c137b7e685000

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末哄陶,一起剝皮案震驚了整個(gè)濱河市帆阳,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌屋吨,老刑警劉巖蜒谤,帶你破解...
    沈念sama閱讀 212,454評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異至扰,居然都是意外死亡鳍徽,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門敢课,熙熙樓的掌柜王于貴愁眉苦臉地迎上來阶祭,“玉大人,你說我怎么就攤上這事直秆”裟迹” “怎么了?”我有些...
    開封第一講書人閱讀 157,921評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵圾结,是天一觀的道長(zhǎng)瑰剃。 經(jīng)常有香客問我,道長(zhǎng)疫稿,這世上最難降的妖魔是什么培他? 我笑而不...
    開封第一講書人閱讀 56,648評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮遗座,結(jié)果婚禮上舀凛,老公的妹妹穿的比我還像新娘。我一直安慰自己途蒋,他們只是感情好猛遍,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般懊烤。 火紅的嫁衣襯著肌膚如雪梯醒。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,950評(píng)論 1 291
  • 那天腌紧,我揣著相機(jī)與錄音茸习,去河邊找鬼。 笑死壁肋,一個(gè)胖子當(dāng)著我的面吹牛号胚,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播浸遗,決...
    沈念sama閱讀 39,090評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼猫胁,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了跛锌?” 一聲冷哼從身側(cè)響起弃秆,我...
    開封第一講書人閱讀 37,817評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎髓帽,沒想到半個(gè)月后菠赚,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,275評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡氢卡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評(píng)論 2 327
  • 正文 我和宋清朗相戀三年锈至,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了晨缴。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片译秦。...
    茶點(diǎn)故事閱讀 38,724評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖击碗,靈堂內(nèi)的尸體忽然破棺而出筑悴,到底是詐尸還是另有隱情,我是刑警寧澤稍途,帶...
    沈念sama閱讀 34,409評(píng)論 4 333
  • 正文 年R本政府宣布阁吝,位于F島的核電站,受9級(jí)特大地震影響械拍,放射性物質(zhì)發(fā)生泄漏突勇。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評(píng)論 3 316
  • 文/蒙蒙 一坷虑、第九天 我趴在偏房一處隱蔽的房頂上張望甲馋。 院中可真熱鬧,春花似錦迄损、人聲如沸定躏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽痊远。三九已至垮抗,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間碧聪,已是汗流浹背冒版。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留逞姿,地道東北人壤玫。 一個(gè)月前我還...
    沈念sama閱讀 46,503評(píng)論 2 361
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像哼凯,于是被迫代替她去往敵國(guó)和親欲间。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評(píng)論 2 350

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

  • 題目: 計(jì)算階乘n!=n*(n-1)*(n-2)*…3*2*1 用遞歸函數(shù)來表示為: def f(x): if ...
    kevin282閱讀 2,253評(píng)論 0 2
  • 學(xué)習(xí)網(wǎng)址:遞歸函數(shù) 注意重點(diǎn): 遞歸函數(shù)的優(yōu)點(diǎn)是定義簡(jiǎn)單断部,邏輯清晰猎贴。理論上,所有的遞歸函數(shù)都可以寫成循環(huán)的方式蝴光,但...
    王詩翔閱讀 368評(píng)論 0 0
  • 下著雨的武漢她渴,天空還是和往常一樣被城市的燈光映的通紅。雨大蔑祟,雨小趁耗,雨停都還是一樣來來往往的路人,都有著各自前行的方...
    Danny___Lee閱讀 239評(píng)論 0 0
  • “漆黑的夜疆虚,稀薄的空氣苛败,寂寞如影隨形,凝視仰望径簿,似夢(mèng)憶真罢屈,內(nèi)心痛苦掙扎我欲掙脫!……瞬間睜開眼篇亭,獨(dú)自漫步星海缠捌,福海...
    閱小咪閱讀 198評(píng)論 0 0
  • 對(duì)于戀愛曼月,你能說些什么 文/夢(mèng)川 這是我戀愛失敗的第三次了,每段戀愛都是無疾而終柔昼。我不知道為什么會(huì)怎么樣哑芹,但事實(shí)...
    夢(mèng)一直在路上閱讀 287評(píng)論 0 1