基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)和算法7:遞歸

1. 遞歸(Recursion)

1.1 概念

遞歸是一種直接或者間接調(diào)用自身函數(shù)。

1.2 本質(zhì)

把問題分解成規(guī)牧辈t?s小的同類問題的子問題

遞歸就是函數(shù)的“套娃”



1.3 套路

  1. 確定遞歸公式
  2. 確定邊界條件

1.4 練習

  1. 遞歸打印1~10
  2. 數(shù)組求和
  3. 階乘n!
  4. 打印第n個斐波那契數(shù)列

使用遞歸模擬for循環(huán)(自增的i和不停的調(diào)用)辙纬。

在第一個月有一對剛出生的小兔子裳凸,在第二個月小兔子變成大兔子并開始懷孕犀盟,第三個月大兔子會生下一對小兔子螃征,并且以后每個月都會生下一對小兔子俊性。 如果每對兔子都經(jīng)歷這樣的出生略步、成熟、生育的過程定页,并且兔子永遠不死趟薄,那么兔子的總數(shù)是如何變化的?


1.5 原理解析

小知識

德羅斯特效應(Droste effect)是遞歸的一種視覺形式典徊,是指一張圖片的某個部分與整張圖片相同杭煎,如此產(chǎn)生無限循環(huán)。


2. 迭代

2.1 概念

迭代(輾轉(zhuǎn)法)是一種不斷用變量的舊值遞推新值的過程卒落。

2.2 本質(zhì)

迭代很多時候就是使用循環(huán)實現(xiàn)羡铲。

2.3 套路

int sum(int n ) {
    int sum =0;
    for(int i = 1 ; i <= n;i++) sum+=n;//求解1~n的和
    return sum;
}
  1. 確定迭代變量:確定一個直接或間接地不斷由舊值推斷新值的變量,如sum儡毕。
  2. 建立迭代關(guān)系式:從變量的舊值推斷到新值的公式也切,如f(n) = f(n-1)+n%=
  3. 對迭代過程進行控制:迭代不可能無限循環(huán)下去,需要對何時退出迭代進行控制雷恃,如i=>n退出循環(huán)疆股。

2.4 練習

  1. 遞歸打印1~10
  2. 數(shù)組求和
  3. 階乘n!
  4. 打印第n個斐波那契數(shù)列

3. 遞歸與迭代比較

3.1 遞歸可能比較耗內(nèi)存

實現(xiàn)函數(shù)printN(int n),打印從1n的所有整數(shù)。

#include <stdio.h>
#include <stdlib.h>

#ifndef RECURSION
void printN(int n){
        for(int i=1;i<=n;++i){
                printf("%d\n",i);
        }
}
#else
void printN(int n){
        if(0 != n) {
                printN(n-1);
                printf("%d\n",n);
        }
}
#endif

int main(int argc,char** argv) {
        if(argc != 2){
                printf("usage:%s <num>\n",argv[0]);
                return 1;
        }
        printN(atoi(argv[1]));
        return 0;
}

編譯執(zhí)行printN(int n)函數(shù)循環(huán)實現(xiàn)

gcc test.c && ./a.out 1000000

編譯執(zhí)行printN(int n)函數(shù)遞歸實現(xiàn)

gcc -DRECURSION test.c && ./a.out 1000000

3.2 遞歸可能比較效率低

斐波那契數(shù)列

  • 遞歸
#include <stdio.h>
#include <stdlib.h>

#ifndef RECURSION
long long Fibonacci(int n) {
    if(n < 1) return 0;
    if(1 == n || 2 == n) return 1;
    return Fibonacci(n-1) + Fibonacci(n-2);
}
#else
long long Fibonacci(int n) {
    if(n<1) return 0;
    long long a = 0;
    long long b = 1;
    for(int i=2;i<=n;i++){
        b += a;
        a = b - a;      
    }
    return b;
}
#endif
int main(int argc,char** argv) {
        if(argc != 2){
                printf("usage:%s <num>\n",argv[0]);
                return 1;
        }
        printf("%lld\n",Fibonacci(atoi(argv[1])));
        return 0;
}

編譯執(zhí)行Fibonacci(int n)函數(shù)循環(huán)實現(xiàn)

gcc test.c && ./a.out 45

編譯執(zhí)行Fibonacci(int n)函數(shù)遞歸實現(xiàn)

gcc -DRECURSION test.c && ./a.out 45

命令time可以測量程序執(zhí)行的時間褂萧。

練習:遞歸打印九九乘法表

void PrintCol(int r,int c){
    if(0==c) return;
    PrintCol(r,c-1);
    printf("%d*%d=%2d ",r,c,r*c);
}
void PrintRow(int r){
    if(0==r) return;
    PrintRow(r-1);
    PrintCol(r,r);
    printf("\n");
    
}

禁止套娃

4. 動態(tài)規(guī)劃

解決遞歸性能問題的一種方法押桃。

70. 爬樓梯

  • 遞歸:樓頂開始思考,自頂而下
class Solution {
public:
    int climbStairs(int n) {
        if(1==n||2==n) return n;
        return climbStairs(n-1)+climbStairs(n-2);
    }
};

遞歸超時导犹,因為存在大量的重復計算唱凯。

  • 動態(tài)規(guī)劃之備忘錄/記憶化
    使用數(shù)組記錄計算過程中的數(shù)值,避免重復計算谎痢。
class Solution {
public:
    vector<int> dp; // 動態(tài)規(guī)劃:備忘錄/記憶化
    int climbStairs(int n) {
        if(dp.empty()) dp.resize(n+1);
        if(1==n||2==n) return n;
        if(0==dp[n]) dp[n] = climbStairs(n-1)+climbStairs(n-2);// 減少重復遞歸計算
        return dp[n];
    }
};
  • 動態(tài)規(guī)劃之自底而上
    樓底開始思考磕昼,自底而上,迭代方式解決問題节猿。
class Solution {
public:
    int climbStairs(int n) {
        if(1==n||2==n) return n;
        int prev = 1; // 臺階1
        int curr = 2; // 臺階2
        for(int i=3;i<=n;++i){
            int res = prev + curr;
            prev =curr;
            curr = res;
        }
        return curr;
    }
};

練習

  1. 鏈表的順序和逆序打印數(shù)據(jù)
  2. 鏈表的反序
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末票从,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子滨嘱,更是在濱河造成了極大的恐慌峰鄙,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,743評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件太雨,死亡現(xiàn)場離奇詭異吟榴,居然都是意外死亡,警方通過查閱死者的電腦和手機囊扳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評論 3 385
  • 文/潘曉璐 我一進店門吩翻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人锥咸,你說我怎么就攤上這事狭瞎。” “怎么了搏予?”我有些...
    開封第一講書人閱讀 157,285評論 0 348
  • 文/不壞的土叔 我叫張陵熊锭,是天一觀的道長。 經(jīng)常有香客問我雪侥,道長球涛,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,485評論 1 283
  • 正文 為了忘掉前任校镐,我火速辦了婚禮亿扁,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘鸟廓。我一直安慰自己从祝,他們只是感情好襟己,可當我...
    茶點故事閱讀 65,581評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著牍陌,像睡著了一般擎浴。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上毒涧,一...
    開封第一講書人閱讀 49,821評論 1 290
  • 那天贮预,我揣著相機與錄音,去河邊找鬼契讲。 笑死仿吞,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的捡偏。 我是一名探鬼主播唤冈,決...
    沈念sama閱讀 38,960評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼银伟!你這毒婦竟也來了你虹?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,719評論 0 266
  • 序言:老撾萬榮一對情侶失蹤彤避,失蹤者是張志新(化名)和其女友劉穎傅物,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體琉预,經(jīng)...
    沈念sama閱讀 44,186評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡董饰,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,516評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了模孩。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,650評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡贮缅,死狀恐怖榨咐,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情谴供,我是刑警寧澤块茁,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站桂肌,受9級特大地震影響数焊,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜崎场,卻給世界環(huán)境...
    茶點故事閱讀 39,936評論 3 313
  • 文/蒙蒙 一佩耳、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧谭跨,春花似錦干厚、人聲如沸李滴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽所坯。三九已至,卻和暖如春挂捅,著一層夾襖步出監(jiān)牢的瞬間芹助,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評論 1 266
  • 我被黑心中介騙來泰國打工闲先, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留状土,地道東北人。 一個月前我還...
    沈念sama閱讀 46,370評論 2 360
  • 正文 我出身青樓饵蒂,卻偏偏與公主長得像声诸,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子退盯,可洞房花燭夜當晚...
    茶點故事閱讀 43,527評論 2 349

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