函数递归学习总结-求n的阶乘,顺序打印⼀个整数的每⼀位,计算一个数的每位之和(递归实现)和第n个斐波那契数的实现!!

之前我们学习了函数,现在我们来总结一下函数中的函数递归,而实现求n的阶乘,顺序打印⼀个整数的每⼀位,第n个斐波那契数的实现等这些代码就需要用到函数递归来实现。

一.什么是递归

递归其实是⼀种解决问题的⽅法,在C语⾔中,递归就是函数⾃⼰调⽤⾃⼰。(让函数在运行中不断的调用本身这个函数,达成另类的“循环”)。

#include <stdio.h>

int main ()
{
printf ( "hehe\n" );
main(); //main 函数中⼜调⽤了 main 函数
return 0 ;
}

上⾯的递归只是为了演⽰递归的基本形式,不是为了解决问 题,代码最终也会陷⼊死递归,导致栈溢出(Stack overflow)。
未处理的异常:

递归的思想:

把⼀个⼤型复杂问题层层转化为⼀个与原问题相似,但规模较⼩的⼦问题来求解;直到⼦问题不能再 被拆分,递归就结束了。所以递归的思考⽅式就是把⼤事化⼩的过程。(个人理解为不断拆分一个问题。) 递归中的递就是递推的意思,归就是回归的意思。

递归在书写的时候是存在限制条件的,当满⾜这个限制条件的时候,递归便不再继续。 而且每次递归调⽤之后越来越接近这个限制条件,直到递归结束!
二. 递归与迭代
在C语⾔中每⼀次函数调⽤,都要需要为本次函数调⽤在栈区申请⼀块内存空间来保存函数调⽤期间 的各种局部变量的值,这块空间被称为运⾏时堆栈,或者函数栈帧。
函数不返回,函数对应的栈帧空间就⼀直占⽤,所以如果函数调⽤中存在递归调⽤的话,每⼀次递归函数调⽤都会开辟属于⾃⼰的栈帧空间,直到函数递归不再继续,开始回归,才逐层释放栈帧空间。 所以如果采⽤函数递归的⽅式完成代码,递归层次太深,就会浪费太多的栈帧空间,也可能引起栈溢 出(stack overflow)的问题
在C语⾔中每⼀次函数调⽤,都要需要为本次函数调⽤在栈区申请⼀块内存空间来保存函数调⽤期间 的各种局部变量的值,这块空间被称为运⾏时堆栈,或者函数栈帧。
函数不返回,函数对应的栈帧空间就⼀直占⽤,所以如果函数调⽤中存在递归调⽤的话,每⼀次递归函数调⽤都会开辟属于⾃⼰的栈帧空间,直到函数递归不再继续,开始回归,才逐层释放栈帧空间。
所以如果采⽤函数递归的⽅式完成代码,递归层次太深,就会浪费太多的栈帧空间,也可能引起栈溢 出(stack overflow)的问题。
如果不想使⽤递归就得想其他的办法,通常就是迭代的⽅式(我个人理解迭代就是循环。)
三.求n的阶乘( 不考虑溢出

首先通过上面可以知道n的阶乘的公式是 n =  n ∗ (n − 1)

然后我们就可以来拆分问题,用递归思想来解决:

假设Fact(n)就是求n的阶乘,那么Fact(n-1)就是求n-1的阶乘:

代码如下:

//递归实现求n的阶乘
int factorial(int n) {
    if (n <= 0) {
        return 1;
    }
    else {
        return n * factorial(n - 1);
    }
}

//非递归实现求n的阶乘
int factorial1(int n) {
    int i = 1;
    int j = 1;
    for (i = 1; i <= n; i++) {
        j *= i;
    }
    return j;
}

int main() {
    int n = 0;
    scanf("%d", &n);
    int m = factorial1(n);
    printf("%d \n", m);
    return 0;
}

四.顺序打印⼀个整数的每⼀位

输⼊⼀个整数,打印这个按照顺序打印整数的每⼀位。
如果n是⼀位数,n的每⼀位就是n⾃⼰,n是超过1位数的话,就得拆分每⼀位 , 1234%10就能得到4,然后1234/10得到123 ,这就相当于去掉了4 然后继续对123%10,就得到了3,再除10去掉3,以此类推不断的 %10 和 \10 操作,直到1234的每⼀位都得到;
代码如下:
//打印一个数的每一位
void Digit(int n) {
    if (n > 9)
    {
        Digit(n / 10);
    }
    printf("%d ", n % 10);
}
int main() {
    int n = 0;
    printf("请输入一个非负整数:\n");
    scanf("%d", &n);
    Digit(n);
    return 0;
}
画图推演如下:
五.计算一个数的每位之和(递归实现)
上面的代码我们打印出来了一个整数的每一位,而我们这次要让他们每一位都加起来,比如输入1234,那么就是1+2+3+4=10,也就是说如果我们输入一个1234,那么就要显示出10;
其实因为我们刚总结了顺序输出每一位的代码,所以我们只需要让它加起来就好了了 ,在上面代码的基础上改进一下就好.
代码如下:
//计算一个数的每位之和(递归实现)
int DigitSum(int n) { 
    if (n > 9)
    {
        return DigitSum(n / 10) + n % 10;
    }
    else {
        return n;
    }
}
int main() {
    int n = 0;
    printf("请输入一个非负整数:\n");
    scanf("%d", &n);
    int sum=DigitSum(n);
    printf("%d \n", sum); 
    return 0;
}
六.求第n个斐波那契数
计算第n个斐波那契数,是不适合使⽤递归求解的,但是斐波那契 数的问题通过是使⽤递归的形式描述的,如下:
Fib(n-1)+Fib(n-2),n>2
所以我们可以得到代码( 我把递归和迭代都写出来一起放出来了

代码如下:

//递归和实现求第n个斐波那契数
int fbnq(int n) {
    if (n<=2) {
        return 1;
    }
    else {
        return fbnq(n - 1) + fbnq(n - 2);
    }
}

//非递归实现求第n个斐波那契数
int  fbnq1(int n) {
    int a = 1;
    int b = 1;
    int c = 1;
    while (n > 2) {
        c = a + b;
        a = b;
        b = c;
        n--;

    }
    return c;
}

//主函数:

int main() {
    int n = 0;
    scanf("%d",&n);
    int a = fbnq1(n);
    printf("%d ", a);
    return 0;
}

 

当我们用递归的方法把n输⼊为50的时候,需要很⻓时间才能算出结果。 递归程序会不断的展开,在展开的过程中,我们很容易就能发现,在递归的过程中会有重复计 算,⽽且递归层次越深,冗余计算就会越多。
计算第40个斐波那契数的时候,使⽤递归⽅式,第3个斐波那契数就被重复计算了 39088169次,这些计算是⾮常冗余的。
所以,我们需要像鹏哥所教授的那样,合理的去选择使用递归的方法,如果用递归写代码,非常容易,就选择递归,但如果使用递归会存在明显缺陷,那就选择使用迭代的方式去处理问题。
加油兄弟们一起努力一起学习!!
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值