从斐波那契数列开始了解递归和尾递归的区别

22 篇文章 0 订阅
10 篇文章 2 订阅

递归函数是指一些会在函数内调用自己的函数,如果在递归函数中,递归调用返回的结果总被直接返回,则称为尾部递归。尾部递归的函数有助将算法转化成函数编程语言,而且从编译器角度来说,亦容易优化成为普通循环。这是因为从电脑的基本面来说,所有的循环都是利用重复移跳到代码的开头来实现的。如果有尾部归递,就只需要叠套一个堆栈,因为电脑只需要将函数的参数改变再重新调用一次。利用尾部递归最主要的目的是要优化。

递归处理斐波那契数列,代码如下:
#include "stdio.h"
#include "math.h"

int factorial(int n);

int main(void)
{
    int i, n, rs;

    printf("请输入斐波那契数n:");
    scanf("%d",&n);

    rs = factorial(n);
    printf("%d \n", rs);

    return 0;
}

// 递归
int factorial(int n)
{
    if(n <= 2)
    {
        return 1;
    }
    else
    {
        return factorial(n-1) + factorial(n-2);
    }
}

运行结果:

请输入斐波那契数n:20
6765

Process returned 0 (0x0) execution time : 3.502 s
Press any key to continue.

尾递归处理斐波那契数列,代码如下:
#include "stdio.h"
#include "math.h"

int factorial(int n);

int main(void)
{
    int i, n, rs;

    printf("请输入斐波那契数n:");
    scanf("%d",&n);

    rs = factorial_tail(n, 1, 1);
    printf("%d ", rs);

    return 0;
}

int factorial_tail(int n,int acc1,int acc2)
{
    if (n < 2)
    {
        return acc1;
    }
    else
    {
        return factorial_tail(n-1,acc2,acc1+acc2);
    }
    return acc2;
}

运行结果:

请输入斐波那契数n:20
6765
Process returned 0 (0x0) execution time : 1.460 s
Press any key to continue.

快了一倍多,再来看看尾递归的每一步是怎么执行的:

int factorial_tail(int n,int acc1,int acc2)
{
    if (n < 2)
    {
        return acc1;
    }
    else
    {
        printf("factorial_tail(%d, %d, %d) \n",n-1,acc2,acc1+acc2);
        return factorial_tail(n-1,acc2,acc1+acc2);
    }
}

运行结果:

请输入斐波那契数n:10
factorial_tail(9, 1, 2)
factorial_tail(8, 2, 3)
factorial_tail(7, 3, 5)
factorial_tail(6, 5, 8)
factorial_tail(5, 8, 13)
factorial_tail(4, 13, 21)
factorial_tail(3, 21, 34)
factorial_tail(2, 34, 55)
factorial_tail(1, 55, 89)
55
Process returned 0 (0x0) execution time : 1.393 s
Press any key to continue.

原本朴素的递归产生的栈的层次像二叉树一样,以指数级增长,但是现在栈的层次却像是数组,变成线性增长了,实在是奇妙,总结起来也很简单,原本栈是先扩展开,然后边收拢边计算结果,现在却变成在调用自身的同时通过参数来计算。

小结:

尾递归的本质是:将单次计算的结果缓存起来,传递给下次调用,相当于自动累积。

为什么尾递归也是递归,却不会造成栈溢出呢?因为编译器通常都会对尾递归进行优化。编译器会发现根本没有必要存储栈信息了,因而会在函数尾直接清空相关的栈。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

askunix_hjh

谢谢请我吃糖~

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

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

打赏作者

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

抵扣说明:

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

余额充值