定义:
斐波那契数列是指这样一个数列: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 种求斐波那契数的方法,各有优缺点。
-
递归法:效率最低,代码最简洁。
-
记忆法:作为递归法的进阶,减少重复计算,大大提高了效率。适用于需要多次计算不同斐波那契数的情况。
-
迭代法:高效并节省了内存。适合大多数应用场景。
-
动态规划:预先计算并存储所有中间结果,适合需要多次查询斐波那契数的场景。