數(shù)據(jù)結(jié)構(gòu)與算法-遞歸

什么是遞歸?

遞歸(英語:Recursion)姚淆,又譯為遞回屡律,在數(shù)學(xué)與計算機科學(xué)中,是指在函數(shù)的定義中使用函數(shù)自身的方法搏讶。遞歸一詞還較常用于描述以自相似方法重復(fù)事物的過程霍殴。

在用代碼實現(xiàn)時来庭,遞歸一般是直接或者間接調(diào)用函數(shù)自身。遞歸的應(yīng)用也很廣泛面睛,比如在 DFS 深度優(yōu)先搜索尊搬、前中后序二叉樹遍歷等。

相關(guān)實例

電影院找座位排號問題

當(dāng)你自己去電影院看電影時(不知道為啥是自己去看電影)幌墓,影廳一般很黑,自己按照電影票上的座位號坐下了蜡饵,健忘的你又把排號忘了胳施,而你又有點強迫癥,就想知道自己坐在哪一排焦辅,怎么辦?看電影票筷登,太黑看不見哩盲,看手機購買訂單,恰巧是線下買的惠险。最簡單的辦法就是問你前面那個人是多少排娱两,如果他也不知道金吗,就再問前前一排摇庙,一直問到第一排的觀眾,每一排的觀眾再把自己所在的排號返回來卫袒,這樣,你就知道自己是第幾排了宝穗,這就是遞歸的思想逮矛。(說得有點啰嗦了)

遞歸的思想就是转砖,把一個問題分解成一個個的子問題和子子問題,然后這些子問題逐級返回,得到最終結(jié)果汞窗。遞歸問題還需要一個終止條件仲吏,比如在電影院這個問題中蝌焚,終止條件就是問到第一排的觀眾。除此之外品腹,每個子問題的求解思路都必須完全一樣红碑。下面總結(jié)一下遞歸需要滿足的幾個條件:

  • 一個問題的解可以分解為幾個子問題的解析珊。
  • 這個問題與分解后的子問題,除了數(shù)據(jù)規(guī)模不同外惧浴,求解思路完全一樣奕剃。
  • 存在遞歸終止條件。

遞歸算法的核心就是根據(jù)一個問題歸納出該問題求解的遞推公式柿顶,對于這個問題嘁锯,假如你在第 f(n) 排,那么 f(n) = f(n-1)+1家乘,這就是遞推公式仁锯,另外終止條件是 n==1笆载,現(xiàn)在用代碼實現(xiàn)一下涯呻。

def cinema(n):
    if n == 1:
        return 1
    return cinema(n-1) +1
result = cinema(14)
print (result)

上臺階問題

上臺階問題也相當(dāng)于斐波那契問題复罐,具體描述是這樣的:有一個 n 級臺階雄家,一個人從第一級往上走趟济,每次只能走 1 級或者 2 級,問有多少種走法顷编。

下面用逆向思維來考慮這個問題媳纬,先看最上面那個臺階 f(n) ,上這級臺階有兩種方法<1>茅糜,一是邁 1 級上去 f(n-1)素挽,二是邁 2 級上去 f(n-2),這兩種方法又分別有兩種相同的子方法<2>缩赛,一次分析下去贮庞,一直到第 1 級臺階和第 2 級臺階結(jié)束。<3>

我標(biāo)出的 <1>、<2>卤材、<3> 恰好符合遞歸的條件,遞推公式為 f(n) = f(n-1)+f(n-2)扇丛,下面用代碼實現(xiàn)一下。

def Fbsq(n):
    if (n < 0):
       return -1
    elif (n == 1):
        return 1
    elif (n == 2):
        return 2
    else:
        return Fbsq(n-1) + Fbsq(n-2)
result = Fbsq(10)
print (result)


警惕堆棧溢出

那節(jié)這種說過较屿,函數(shù)調(diào)用是通過棧來實現(xiàn)的,遞歸需要不斷地進行函數(shù)調(diào)用购啄,相當(dāng)于不斷地壓棧狮含,很容易造成堆棧溢出,會造成系統(tǒng)性的崩潰几迄,所以遞歸求解不適合用在數(shù)據(jù)規(guī)模大的地方映胁。

為了防止堆棧溢出的出現(xiàn)屿愚,可以限制遞歸的深度务荆,但治標(biāo)不治本,數(shù)據(jù)規(guī)模大的話娱据,還是不用遞歸為好中剩。

警惕重復(fù)計算

看一個這個例子:


重復(fù)計算.jpg

里面 f(3) 被多次計算结啼,會無故消耗代碼運行時間郊愧,為了避免這種重復(fù)計算的情況出現(xiàn)井佑,可以將已經(jīng)計算的 f(n) 保存在一個散列表中,當(dāng)調(diào)用 f(n) 時焦蘑,可以先看看散列表中有沒有例嘱,沒有的話再計算狡逢。

遞歸代碼寫成非遞歸的形式

遞歸代碼都能寫成非遞歸的形式拼卵,例如電影院問題间学,寫成非遞歸的形式為:

def Ncinema(n,result):
    for i in range(n):
        result += 1
    return result
number = Ncinema(14,0)
print (number)

小結(jié)

遞歸需要滿足三個條件殷费,遞歸用在數(shù)據(jù)規(guī)模較小的情況下详羡,要注意堆棧溢出和重復(fù)計算,每個遞歸都能寫成非遞歸的形式嘿悬。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末实柠,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子善涨,更是在濱河造成了極大的恐慌窒盐,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,907評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件钢拧,死亡現(xiàn)場離奇詭異蟹漓,居然都是意外死亡,警方通過查閱死者的電腦和手機源内,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評論 3 395
  • 文/潘曉璐 我一進店門葡粒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人膜钓,你說我怎么就攤上這事嗽交。” “怎么了夫壁?”我有些...
    開封第一講書人閱讀 164,298評論 0 354
  • 文/不壞的土叔 我叫張陵忿磅,是天一觀的道長。 經(jīng)常有香客問我吨些,道長,這世上最難降的妖魔是什么斩萌? 我笑而不...
    開封第一講書人閱讀 58,586評論 1 293
  • 正文 為了忘掉前任姆吭,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘昂灵。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,633評論 6 392
  • 文/花漫 我一把揭開白布吊履。 她就那樣靜靜地躺著,像睡著了一般居砖。 火紅的嫁衣襯著肌膚如雪循集。 梳的紋絲不亂的頭發(fā)上间螟,一...
    開封第一講書人閱讀 51,488評論 1 302
  • 那天服猪,我揣著相機與錄音,去河邊找鬼逻卖。 笑死灭返,一個胖子當(dāng)著我的面吹牛罚缕,可吹牛的內(nèi)容都是我干的蚓聘。 我是一名探鬼主播,決...
    沈念sama閱讀 40,275評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼袋毙,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起背零,我...
    開封第一講書人閱讀 39,176評論 0 276
  • 序言:老撾萬榮一對情侶失蹤毛雇,失蹤者是張志新(化名)和其女友劉穎灵疮,沒想到半個月后蒿赢,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體晾腔,經(jīng)...
    沈念sama閱讀 45,619評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡席怪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,819評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了舱呻。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,932評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡晚树,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出婚瓜,到底是詐尸還是另有隱情,我是刑警寧澤胡陪,帶...
    沈念sama閱讀 35,655評論 5 346
  • 正文 年R本政府宣布捧书,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏慎式。R本人自食惡果不足惜幕屹,卻給世界環(huán)境...
    茶點故事閱讀 41,265評論 3 329
  • 文/蒙蒙 一蓝丙、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧望拖,春花似錦渺尘、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至盔沫,卻和暖如春医咨,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背架诞。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評論 1 269
  • 我被黑心中介騙來泰國打工拟淮, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人侈贷。 一個月前我還...
    沈念sama閱讀 48,095評論 3 370
  • 正文 我出身青樓惩歉,卻偏偏與公主長得像等脂,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子撑蚌,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,884評論 2 354

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