赞
踩
斐波那契数列(Fibonacci数列)是数学家斐波那契以研究兔子繁殖为例研究的数列,故称“兔子数列”,又称为黄金分割数列。
对于斐波那契额数列的求解,常用的有两种方式:循环与递归,本文将分别对两种方式进行思路分析与代码实现。
观察图中的斐波那契额数列,从第三项开始,每一项都是前两项之和,循环往复,找到了循环的规律,我们不难将此数列进行划分,每两项为一组,分别定义为 f1、f2,则其下一组的 f1(新) = f1(旧) + f2(旧),f2(新) = f1(新) + f2(旧),也就是说,我们求解某一项,只需求解出它所在的那一组的 f1 与 f2,根据 n 的奇偶性输出 f1 或 f2 即可。
考虑到需要用户进行输入,专门增加了输入的纠错功能,保证程序正常运行。
代码如下(示例):
/* Alkaid#3529 */
#include <iostream>
using namespace std;
/* 输出斐波那契额数列的前n项 循环方式 */
int fibonacci_circulate(int n);
int main()
{
int n;
cout << "请输入fibonacci数列的项数:\n";
for (;;)
{
cin >> n;
if (cin.fail())
{
cin.clear();
cin.ignore(1024, '\n');
cout << "输入错误";
}
else
break;
}
cout << "\n通过循环可得:\n";
cout << "fibonacci数列第" << n << "项为:" << fibonacci_circulate(n) << endl;
return 0;
}
int fibonacci_circulate(int n)
{
long long f1 = 1, f2 = 1;
int time = (n + 1) / 2;
for (int i = 1; i < time; i++)
{
f1 = f1 + f2;
f2 = f2 + f1;
}
if (n % 2 == 0)
return f2;
else
return f1;
}
运行代码后,我们可以快速得到想要求解的对应值:
如果需要详细查看每一项的值,只需在循环过程中同步输出 f1 与 f2 即可。
递归是常见的思路之一,究其本质,其实就是把一个大型复杂问题层层转化为一个与原问题结构相同,但是规模更小的问题,问题被拆解成子问题后,递归调用继续进行,直到子问题无需进一步递归就可以解决的地步为止。
我们观察此问题,不难发现,每一项的求解可以转化为对其前两项的求解,层层嵌套,因此,我们只需设定 n=1 和 n=2 时的 fibonacci 数列的值即可。
代码如下(示例):
/* Alkaid#3529 */
#include <iostream>
using namespace std;
/* 输出斐波那契额数列的前n项 递归方式 */
int fibonacci_recursion(int n);
int main()
{
int n;
cout << "请输入fibonacci数列的项数:\n";
for (;;)
{
cin >> n;
if (cin.fail())
{
cin.clear();
cin.ignore(1024, '\n');
cout << "输入错误";
}
else
break;
}
cout << "\n通过递归可得:\n";
cout << "fibonacci数列第" << n << "项为:" << fibonacci_recursion(n) << endl;
return 0;
}
int fibonacci_recursion(int n)
{
if (n == 1)
return 1;
if (n == 2)
return 1;
else
return fibonacci_recursion(n - 1) + fibonacci_recursion(n - 2);
}
运行代码后,我们可以快速得到想要求解的对应值:
得到的结果与循环方式并无二致。
循环是最为简单直接的求解方式,复杂度并不高,因此所需时间也大幅少于递归方式,这一点在项数较少的时候体现的并不明显,一旦项数增加至40左右,两者的时间差肉眼可见。
我们可以对代码稍做加工,让其体现得更为直观。
代码如下(示例):
/* Alkaid#3529 */
#include <iostream>
#include<windows.h>
using namespace std;
/* 输出斐波那契额数列的前n项 循环方式 */
int fibonacci_circulate(int n);
/* 输出斐波那契额数列的前n项 递归方式 */
int fibonacci_recursion(int n);
int main()
{
int n;
cout << "请输入fibonacci数列的项数:\n";
for (;;)
{
cin >> n;
if (cin.fail())
{
cin.clear();
cin.ignore(1024, '\n');
cout << "输入错误";
}
else
break;
}
DWORD start_time_circulate = GetTickCount64();
{
cout << "\n通过循环可得:\n";
cout << "fibonacci数列第" << n << "项为:" << fibonacci_circulate(n) << endl;
}
DWORD end_time_circulate = GetTickCount64();
cout << "The run time is: " << (end_time_circulate - start_time_circulate) << " ms!" << endl;
DWORD start_time_recursion = GetTickCount64();
{
cout << "\n通过递归可得:\n";
cout << "fibonacci数列第" << n << "项为:" << fibonacci_recursion(n) << endl;
}
DWORD end_time_recursion = GetTickCount64();
cout << "The run time is: " << (end_time_recursion - start_time_recursion) << " ms!" << endl;
return 0;
}
int fibonacci_circulate(int n)
{
long long f1 = 1, f2 = 1;
int time = (n + 1) / 2;
for (int i = 1; i < time; i++)
{
f1 = f1 + f2;
f2 = f2 + f1;
}
if (n % 2 == 0)
return f2;
else
return f1;
}
int fibonacci_recursion(int n)
{
if (n == 1)
return 1;
if (n == 2)
return 1;
else
return fibonacci_recursion(n - 1) + fibonacci_recursion(n - 2);
}
运行代码,我们可以明显观察到,当 n 的值较小时,两种方式差距不大:
但是当 n 的值增加到50时,两者的差距就变得不可忽略了:
因此,在大多数情况下,递归只是一种思路,循环更为常用。至于递归为何会比循环耗时更多,关注我的频道,为你详细解答!
斐波那契额数列不仅是循环与递归的经典习题,也是数据结构与算法的内容之一,熟练掌握 fibonacci 的解题思路对我们往后的学习十分有益,后续我也会推出数据结构与算法的相关内容,希望对大家的学习有所帮助。
最后我是Alkaid#3529,期待你的关注!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。