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

定义:

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

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

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

求解

方法 1. 递归法

代码

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

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

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

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

方法 2. 记忆法

代码

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

go 复制代码
/**
 * @ 方法 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. 迭代法

代码

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

go 复制代码
/**
 * @ 方法 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. 动态规划

代码

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

go 复制代码
/**
 * @ 方法 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];
}
分析
  • 系统化记录结果,适合多次查询。

  • 需要额外的内存空间。

完整代码

go 复制代码
/**
 * @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;
}

运行结果

总结

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

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

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

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

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

相关推荐
Leaf吧2 分钟前
分布式定时任务(xxl-job)
java·分布式
纪元A梦15 分钟前
华为OD机试真题——绘图机器(2025A卷:100分)Java/python/JavaScript/C++/C/GO最佳实现
java·javascript·c++·python·华为od·go·华为od机试题
钢铁男儿17 分钟前
C# 深入理解类:面向对象编程的核心数据结构
开发语言·数据结构·c#
24k小善29 分钟前
FlinkSql入门与实践
java·大数据·flink·云计算
CodeCraft Studio42 分钟前
Excel处理控件Spire.XLS系列教程:Java设置Excel活动工作表或活动单元格
java·python·excel
Doker 多克43 分钟前
Python-Django系列—部件
开发语言·python
Felven1 小时前
A. Everybody Likes Good Arrays!
数据结构·算法
江沉晚呤时1 小时前
深入解析 ASP.NET Core 中的 ResourceFilter
开发语言·c#·.net·lucene
huangyuchi.1 小时前
【C++11】Lambda表达式
开发语言·c++·笔记·c++11·lambda·lambda表达式·捕捉列表
瓯雅爱分享1 小时前
任务管理系统,Java+Vue,含源码与文档,科学规划任务节点,全程督办保障项目落地提效
java·mysql·vue·软件工程·源代码管理