斐波那契数列的两种实现方式 C++实现

文章目录

  • 前言
  • 一、循环方式
    • 1.思路分析
    • 2.代码实现
  • 二、递归方式
    • 1.思路分析
    • 2.代码实现
  • 三、两种方式对比
  • 总结


前言

斐波那契数列(Fibonacci数列)是数学家斐波那契以研究兔子繁殖为例研究的数列,故称“兔子数列”,又称为黄金分割数列。

对于斐波那契额数列的求解,常用的有两种方式:循环与递归,本文将分别对两种方式进行思路分析与代码实现。

一、循环方式

1.思路分析

观察图中的斐波那契额数列,从第三项开始,每一项都是前两项之和,循环往复,找到了循环的规律,我们不难将此数列进行划分,每两项为一组,分别定义为 f1、f2,则其下一组的 f1(新) = f1(旧) + f2(旧),f2(新) = f1(新) + f2(旧),也就是说,我们求解某一项,只需求解出它所在的那一组的 f1 与 f2,根据 n 的奇偶性输出 f1 或 f2 即可。

考虑到需要用户进行输入,专门增加了输入的纠错功能,保证程序正常运行。

2.代码实现

代码如下(示例):

/* Alkaid#3529 */

#include 
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;
}

运行代码后,我们可以快速得到想要求解的对应值:

斐波那契数列的两种实现方式 C++实现_第1张图片
如果需要详细查看每一项的值,只需在循环过程中同步输出 f1 与 f2 即可。

二、递归方式

1.思路分析

递归是常见的思路之一,究其本质,其实就是把一个大型复杂问题层层转化为一个与原问题结构相同,但是规模更小的问题,问题被拆解成子问题后,递归调用继续进行,直到子问题无需进一步递归就可以解决的地步为止。

我们观察此问题,不难发现,每一项的求解可以转化为对其前两项的求解,层层嵌套,因此,我们只需设定 n=1 和 n=2 时的 fibonacci 数列的值即可。

2.代码实现

代码如下(示例):

/* Alkaid#3529 */

#include 
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 
#include
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 的值较小时,两种方式差距不大:

斐波那契数列的两种实现方式 C++实现_第2张图片
但是当 n 的值增加到50时,两者的差距就变得不可忽略了:

斐波那契数列的两种实现方式 C++实现_第3张图片

因此,在大多数情况下,递归只是一种思路,循环更为常用。至于递归为何会比循环耗时更多,关注我的频道,为你详细解答!


总结

斐波那契额数列不仅是循环与递归的经典习题,也是数据结构与算法的内容之一,熟练掌握 fibonacci 的解题思路对我们往后的学习十分有益,后续我也会推出数据结构与算法的相关内容,希望对大家的学习有所帮助。

最后我是Alkaid#3529,期待你的关注!

你可能感兴趣的:(C++,Foundation,c++,算法)