斐波那契数求解引发的思考

定义: 

斐波那契数列是指这样一个数列:0,1,1,2,3,5,8,13,21,34,55……这个数列从第3项开始 ,每一项都等于前两项之和。

  • 表达式:F(n) = F(n-1) + F(n-2) 。

  • 基例:F(0) = 0F(1) = 1 。

求解 

方法 1. 递归法

代码

使用递归的方法,编写代码如下

/**
 * @ 方法 1:递归的方法
 * @ num - 用于求解的斐波那契数参数
 * @ 返回结果
 * */ 
int fibonacci_1(int num)
{
    if (num < 2)
        return num;
    else 
        return (fibonacci_1(num-1) + fibonacci_1(num-2));
}
分析
  • 因为重复计算了很多相同的斐波那契数,以上程序实现效率非常低。

  • 在嵌入式系统中使用,由于栈空间的限制,递归调用可能会导致栈溢出。

  • 递归会产生额外的函数调用开销(保存和恢复寄存器状态)。

方法 2. 记忆法

代码

在递归的基础上,记忆已计算过的斐波拉契数,避免重复计算。编写代码如下

/**
 * @ 方法 2:递归 + 记忆的方法
 * @ num - 用于求解的斐波那契数参数     res - 记录求过的斐波那契数
 * @ 返回结果
 * */ 
int fibonacci_2(int num, int *res)
{
    int result = 0;

    if (num < 2) {
        result = num;
    } elseif (res[num] != -1) {    /* 判断是否求解过 */
        result = res[num];
    } else {
        result = (fibonacci_2(num-1, res) + fibonacci_2(num-2, res));
        res[num] = result;        /* 记录斐波那契数的值 */
    }

    return result;
}
分析
  • 通过记录求得的斐波拉契数值,避免重复迭代计算。

  • 因为需要引入数组记录数据,所以会有一定的额外空间开销。

  • 注意:申请数组空间需要大于所求的斐波拉契数值。

方法 3. 迭代法

代码

使用循环的方式求解,减少递归带来的栈开销。编写代码如下

/**
 * @ 方法 3:迭代的方法
 * @ num - 用于求解的斐波那契数参数
 * @ 返回结果
 * */ 
int fibonacci_3(int num)
{
    int a = 0, b = 1, tmp;

    if (num > 0) {
        while (num--) {
            tmp = a;
            a = b;
            b = tmp + b;
        }     
    }
    return a;
}
分析
  • 简单高效,适合大多数应用场景。

  • 减少递归带来的栈空间开销。

  • 没有递归代码容易理解。

方法 4. 动态规划

代码

预先计算并存储所有中间结果,以便快速查询。编写代码如下

/**
 * @ 方法 4:动态规划的方法
 * @ num - 用于求解的斐波那契数参数
 * @ 返回结果
 * */ 
int fibonacci_4(int num)
{
    int i, res[MAX_NUM];

    res[0] = 0;
    res[1] = 1;
    if (num >= 2) {
        for (i=2; i<=num; i++) {
            res[i] = res[i-1] + res[i-2];
        }
    }
    return res[num];
}
分析
  • 系统化记录结果,适合多次查询。

  • 需要额外的内存空间。

完整代码 

/**
 * @Filename : fibonacci.c
 * @Revision : $Revision: 1.00 $
 * @Author : Feng(更多编程相关的知识和源码见微信公众号:不只会拍照的程序猿,欢迎订阅)
 * @Description : 计算斐波那契数 f(n) = f(n-1) + f(n-2)  f(0) = 0, f(1) = 1
**/

#include <stdio.h>
#include <string.h>

#define MAX_NUM     100  

/**
 * @ 方法 1:递归的方法
 * @ num - 用于求解的斐波那契数参数
 * @ 返回结果
 * */
int fibonacci_1(int num)
{
    if (num < 2)
        return num;
    else
        return (fibonacci_1(num-1) + fibonacci_1(num-2));
}

/**
 * @ 方法 2:递归 + 记忆的方法
 * @ num - 用于求解的斐波那契数参数     res - 记录求过的斐波那契数
 * @ 返回结果
 * */
int fibonacci_2(int num, int *res)
{
    int result = 0;

    if (num < 2) {
        result = num;
    } elseif (res[num] != -1) {    /* 判断是否求解过 */
        result = res[num];
    } else {
        result = (fibonacci_2(num-1, res) + fibonacci_2(num-2, res));
        res[num] = result;        /* 记录斐波那契数的值 */
    }

    return result;
}

/**
 * @ 方法 3:迭代的方法
 * @ num - 用于求解的斐波那契数参数
 * @ 返回结果
 * */
int fibonacci_3(int num)
{
    int a = 0, b = 1, tmp;

    if (num > 0) {
        while (num--) {
            tmp = a;
            a = b;
            b = tmp + b;
        }     
    }
    return a;
}

/**
 * @ 方法 4:动态规划的方法
 * @ num - 用于求解的斐波那契数参数
 * @ 返回结果
 * */
int fibonacci_4(int num)
{
    int i, res[MAX_NUM];

    res[0] = 0;
    res[1] = 1;
    if (num >= 2) {
        for (i=2; i<=num; i++) {
            res[i] = res[i-1] + res[i-2];
        }
    }
    return res[num];
}

/**
 * @ 主函数
 * */
int main(void)
{
    int num = 10, i, res[MAX_NUM] = { 0 };

    printf ("-------方法1 递归法------\n");
    printf ("fibonacci_1(%d) = %d\n", num, fibonacci_1(num));

    printf ("-------方法2 记忆法------\n");
    memset(res, -1, sizeof(res));
    res[0] = 0;
    res[1] = 1;
    printf ("fibonacci_2(%d) = %d\n", num, fibonacci_2(num, res));

    printf ("-------方法3 迭代法------\n");
    printf ("fibonacci_3(%d) = %d\n", num, fibonacci_3(num));

    printf ("-------方法4 动态规划------\n");
    printf ("fibonacci_4(%d) = %d\n", num, fibonacci_4(num));
    
    return0;
}

运行结果 


921b9c181ace462d95c1c63d5adf20e7.png

总结 

以上 4 种求斐波那契数的方法,各有优缺点。

  • 递归法:效率最低,代码最简洁。

  • 记忆法:作为递归法的进阶,减少重复计算,大大提高了效率。适用于需要多次计算不同斐波那契数的情况。

  • 迭代法:高效并节省了内存。适合大多数应用场景。

  • 动态规划:预先计算并存储所有中间结果,适合需要多次查询斐波那契数的场景。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

不只会拍照的程序猿

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

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

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

打赏作者

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

抵扣说明:

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

余额充值