基础数据结构和算法7:递归

1. 递归(Recursion)

1.1 概念

递归是一种直接或者间接调用自身函数。

1.2 本质

把问题分解成规模缩小的同类问题的子问题

递归就是函数的“套娃”



1.3 套路

  1. 确定递归公式
  2. 确定边界条件

1.4 练习

  1. 递归打印1~10
  2. 数组求和
  3. 阶乘n!
  4. 打印第n个斐波那契数列

使用递归模拟for循环(自增的i和不停的调用)。

在第一个月有一对刚出生的小兔子,在第二个月小兔子变成大兔子并开始怀孕,第三个月大兔子会生下一对小兔子,并且以后每个月都会生下一对小兔子。 如果每对兔子都经历这样的出生、成熟、生育的过程,并且兔子永远不死,那么兔子的总数是如何变化的?


1.5 原理解析

小知识

德罗斯特效应(Droste effect)是递归的一种视觉形式,是指一张图片的某个部分与整张图片相同,如此产生无限循环。


2. 迭代

2.1 概念

迭代(辗转法)是一种不断用变量的旧值递推新值的过程。

2.2 本质

迭代很多时候就是使用循环实现。

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. 建立迭代关系式:从变量的旧值推断到新值的公式,如f(n) = f(n-1)+n%=
  3. 对迭代过程进行控制:迭代不可能无限循环下去,需要对何时退出迭代进行控制,如i=>n退出循环。

2.4 练习

  1. 递归打印1~10
  2. 数组求和
  3. 阶乘n!
  4. 打印第n个斐波那契数列

3. 递归与迭代比较

3.1 递归可能比较耗内存

实现函数printN(int n),打印从1n的所有整数。

#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;
}

编译执行printN(int n)函数循环实现

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

编译执行printN(int n)函数递归实现

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

3.2 递归可能比较效率低

斐波那契数列

  • 递归
#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;
}

编译执行Fibonacci(int n)函数循环实现

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

编译执行Fibonacci(int n)函数递归实现

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

命令time可以测量程序执行的时间。

练习:递归打印九九乘法表

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. 动态规划

解决递归性能问题的一种方法。

70. 爬楼梯

  • 递归:楼顶开始思考,自顶而下
class Solution {
public:
    int climbStairs(int n) {
        if(1==n||2==n) return n;
        return climbStairs(n-1)+climbStairs(n-2);
    }
};

递归超时,因为存在大量的重复计算。

  • 动态规划之备忘录/记忆化
    使用数组记录计算过程中的数值,避免重复计算。
class Solution {
public:
    vector<int> dp; // 动态规划:备忘录/记忆化
    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];
    }
};
  • 动态规划之自底而上
    楼底开始思考,自底而上,迭代方式解决问题。
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. 链表的顺序和逆序打印数据
  2. 链表的反序
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,039评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,426评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,417评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,868评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,892评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,692评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,416评论 3 419
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,326评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,782评论 1 316
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,957评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,102评论 1 350
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,790评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,442评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,996评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,113评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,332评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,044评论 2 355

推荐阅读更多精彩内容

  • 【程序1】 题目:古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔...
    开心的锣鼓阅读 3,320评论 0 9
  • 50道经典Java编程练习题,将数学思维运用到编程中来。抱歉哈找不到文章的原贴了,有冒犯的麻烦知会声哈~ 1.指数...
    OSET我要编程阅读 6,962评论 0 9
  • Java经典问题算法大全 /*【程序1】 题目:古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子...
    赵宇_阿特奇阅读 1,869评论 0 2
  • 1.把二元查找树转变成排序的双向链表 题目: 输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。 要求不...
    曲终人散Li阅读 3,319评论 0 19
  • 风中的青春 近看 青春在流水间 触手可及 远看 青春在白云端 遥不可及 回头看 青春在夜风里 夜色淹没了的青春 风...
    新观点读书阅读 121评论 0 0