不同于你所熟知的“循环”,玩转函数递归

什么是函数递归?

程序调用自身的编程技巧称为递归( recursion)。 递归做为一种算法在程序设计语言中广泛应用。一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。
递归的主要思考方式在于:把大事化小

函数递归的必要条件

  • 存在限制条件,当满足这个限制条件的时候,递归便不再继续。
  • 每次递归调用之后越来越接近这个限制条件。

关于无限递归下去所出现的问题

每一次调用函数时都会在内存中(栈区)开辟空间,当调用还没有返回时,原先开辟的空间依然存在,所以无限调用一直不返回,栈区的内存一直被占用,当超出内存空间时就会栈溢出。

函数栈帧的越出简洁图如下:
在这里插入图片描述

递归例题,理清递归的逻辑

  • 接受一个整型值(无符号),按照顺序打印它的每一位。 例如: 输入:1234,输出 1 2 3 4.
    逻辑分解图:
    在这里插入图片描述
    实现过程:
#include<stdio.h>
void Print(unsigned int n)
{
    if(n>9)
    {
        Print(n/10);
    }
    printf("%d",n%10);
}
int main()
{
    unsigned int num=0;
    scanf("%d",&num);
    Print(num);
}

递归过程分解:
在这里插入图片描述

  • 编写函数不允许创建临时变量,求字符串长度
    逻辑分解图:
    在这里插入图片描述
    实现过程:
int My_strlen(char *parr)
{
    if(*parr!='\0')
    {
    //注意这里不能parr++,后置++传过去的不是下一个元素的地址
        return 1+My_strlen(parr+1);
    }
    else
    {
        return 0;
    }
}
#include<stdio.h>
int main()
{
    char arr[10]="abc";
    int ret=0;
    ret=My_strlen(arr);
    return 0;
}

递归分解过程:
在这里插入图片描述

递归与迭代(循环)

  • 求n的阶乘
int Fac(int n)//迭代
{
    int i=0;
    int ret=1;
    for(i=1;i<=n;i++)
    {
        ret*=i;
    }
    return ret;
}
int Fac(int n)//递归
{
    if(n<=1)
    return 1;
    else
    return n*Fac(n-1);
}
  • 但是一些问题不适合用递归与迭代的方法进行解决,如求第n个斐波那契数列数
    什么是斐波那契数列?
    在这里插入图片描述
    代码实现:
int Fib(int n)
{
    if(n<=2)
    return 1;
    else
    return Fib(n-1)+Fib(n-2);
}
int main()
{
    int n=0;
    scanf("%d",&n);
    int ret=Fib(n);
    printf("%d\n",ret);
}
  • 注意:
    1、在使用 Fib 这个函数的时候如果我们要计算第50个斐波那契数字的时候特别耗费时间。

    2、使用 factorial 函数求10000的阶乘(不考虑结果的正确性),程序会崩溃。

  • 为什么会出现这样的原因?
    如果要求第50个,会将50拆成48和49;而48又拆成46和47,49拆成47和48,就这样依次进行下去,需要大量的时间冗余和内存消耗,所以会出现上述的原因。

  • 解决方法:
    1、将递归改写成非递归。
    2、使用static对象替代nonstatic局部对象。在递归函数设计中,可以使用static对象替代nonstatic局部对象(即栈对象),这不仅可以减少每次递归调用和返回时产生和释放nonstatic对象的开销,而且static对象还可以保存递归调用的中间状态,并且可为各个调用层所访问。

int Fib(int n)
{
    int a=1;
    int b=1;
    int c=1;
    while(n>2)
    {
        c=a+b;
        a=b;
        b=c;
        n--;
    }
    return c;
}

什么时候使用递归?

1、当解决一个问题递归和非递归都可以使用,且没有明显问题,那就可以使用递归

2、当解决一个问题递归写起来很简单,非递归比较复杂,且递归没有明显问题,那就用递归。

3、如果说用递归解决问题写起来简单,但是有明显问题,那就不能使用。

递归注意的事项

1、许多问题是以递归的形式进行解释的,这只是因为它比非递归的形式更为清晰。

2、但是这些问题的迭代实现往往比递归实现效率更高,虽然代码的可读性稍微差些。

3、当一个问题相当复杂,难以用迭代实现时,此时递归实现的简洁性便可以补偿它所带来的运行时开销。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jiawen_captial

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值