本期介绍🍖
主要介绍:什么是斐波那契数列,递归实现求斐波那契数列第n项值,递归法为什么不适合求斐波那契数,用迭代法实现求斐波那契数列的值👀。
文章目录
- 1. 斐波那契数列是什么?
- 2. 题目
- 2. 递归实现思路
- 3. 迭代实现思路
1. 斐波那契数列是什么?
斐波那契数列(Fibonacci sequence),又称黄金分割数列,因数学家莱昂纳多·斐波那契(Leonardo Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”。斐波那契数列指的是这样一个数列:1,1,2,3,5,8,13,21,34,55,89…这个数列从第3项开始,之后的每一项都等于前两项之和。
2. 题目
求解:斐波那契数列第n项的值。
2. 递归实现思路
斐波那契数有一个特性,每一个斐波那契数都是前两个斐波那契数的和。由此当想要求第n个斐波那契数时,就可以写成:Fib(n) = Fib(n-1)+Fib(n-2)
。这样求第n个斐波那契数,就转化为求第(n-1)和第(n-2)个斐波那契数了。如此就可以层层转化下去,直至求第1和第2个斐波那契数,公式如下:
实现代码如下:
#include<stdio.h>
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 back = Fib(n);
printf("第%d个斐波那契数为>:%d\n", n, back);
return 0;
}
当使用上面的代码计算第50个斐波那契数时,会发现运行的代码需要非常久的时间才能算出来。那为什么会这样呢?如下图所示:
真正导致计算第50个斐波那契时间过长的原因,是由于在递归的过程中会有重复计算,而且层数越深,冗余计算就越多。可以通过计算求第30个斐波那契数中Fib(3)被重复调用的次数,代码如下:
#include<stdio.h>
int count = 0;
int Fib(int n)
{
if (n == 3)
count++;
if (n <= 2)
return 1;
else
return Fib(n - 1) + Fib(n - 2);
}
int main()
{
int n = 0;
scanf("%d", &n);
int back = Fib(n);
printf("计算Fib(3)的次数>:%d\n", count);
printf("第%d个斐波那契数为>:%d\n", n, back);
return 0;
}
当计算第30个斐波那契数,重复计算Fib(3)的次数高达317811,所以可以看出用递归实现计算斐波那契数,是非常不明智的,于是思考如何使用迭代解决。
大家因该有一个疑惑,重复如此多次递归调用,斐波那契数列为什么没有出现栈溢出的情况?值得注意,不是重复计算多了就会出现栈溢出,而是同时压栈的层数太多才会导致栈溢出。虽然一眼望去该函数需要递归大约 249 次,但这并不代表该函数同时压栈的层数深。因为Fib()
的执行逻辑是,先递推一条分支到头,再逐步回归,再递推如此往复。Fib(50)递归最深也就50个调用堆栈。
3. 迭代实现思路
除了递归法还可以通过迭代法来求第n项的斐波那契数列,因为不管是递归还是迭代其本质都是循环,无非就是正向思维和反向思维之区别。
迭代法思路:从项斐波那契数的第1项开始,然后通过每一项都等于前两项之和,不断的迭代就可以递推出第n项斐波那契数的值了。
int Fib(int n)
{
int num1 = 1;
int num2 = 1;
int num3 = 1;
while (n >= 3)
{
num3 = num1 + num2;
num1 = num2;
num2 = num3;
n--;
}
return num3;
}
int main()
{
int n = 0;
scanf("%d", &n);
int back = Fib(n);
printf("第%d个斐波那契数为>:%d\n", n, back);
return 0;
}
如上所示,当计算第50个斐波那契数,一瞬间就的出来了,只不过int
类型存不下这个数,打印结果才是一个负数。
在很多实际问题中,我们可以用递归来解决也可以用非递归来是解决,而有时用递归去解决问题的时候会存在一些问题,就譬如刚刚求斐波那契数列的问题的效率低下。所以碰到这类问题时我们就不能再使用递归的方法了,我们需要另辟蹊径从另一个角度来思考对策,就譬如迭代的方法。
这份博客👍如果对你有帮助,给博主一个免费的点赞以示鼓励欢迎各位🔎点赞👍评论收藏⭐️,谢谢!!!
如果有什么疑问或不同的见解,欢迎评论区留言欧👀。