Fibonacci数列的实现与改进

Fibonacci数列是初学者接触到的一道关于for循环的习题,它的实现比较简单

int main()
{
	int pos = 0;
	cout << "Please enter a position:";
	cin >> pos;
	int elem = 1;
	int n_1 = 1, n_2 = 1;
	for (int ix = 3; ix <= pos; ix++)
	{
		elem = n_1 + n_2;
		n_2 = n_1;
		n_1 = elem;
	}
	cout << "element " << pos << " is " << elem << endl;
	return 0;
}

但我们通常不在主函数内实现,于是我们声明一个int fibon_elem(int pos)函数,数列的实现与上面相同

如果用户输入了0或者一个很大的数,我们的程序就可能出错,Fibonacci数列是没有尽头的,但我们的代码必须设置一个终点,这里我设为1024

当用户没有输入0-1024之间的值时,我们需要给出友好的交互信息,提醒用户出现了错误,于是我们将fibon_seq()函数的返回值类型改为bool(感觉变高级了有木有),在主函数中进行交互动作的实现

//这里的声明未写出参数的名称,这是没有问题的,因为参数名称只有在函数内使用参数是才是必要的
bool fibon_elem(int,int&);

bool fibon_elem(int pos, int& elem)
{
	//判断pos的合法性
	if (pos <= 0 || pos >= 1024)
	{
         return false;
		 elem = 0;
	}
	elem = 1;
	int n_1 = 1, n_2 = 1;
	//只有pos>=3时才进入循环,否则elem=1
	for (int ix = 3; ix <= pos; ix++)
	{
		elem = n_1 + n_2;
		n_2 = n_1;
		n_1 = elem;
	}
	return true;
}

int main()
{
	int elem = 0;
	int pos = 0;
	cout << "please enter a position: ";
	cin >> pos;
	if (!fibon_elem(pos, elem))//pos不合法
		cout << "sorry the position is inexistence";
	else
		cout << "element " << pos << " is " << elem << endl;
    return 0;
}

*在传递参数的时候,使用了&(引用),与指针的用途相似

为了让用户得到pos之前的Fibonacci数,我们需要定义一个打印函数,将数列输出

//声明一个打印函数
bool print_elem(int);

bool print_elem(int pos)
{
	//判断位置合法性
	if (pos <= 0 || pos >= 1024)
	{
		cout <<endl<< "invaild position: " << pos
			<< ",cannot handle the request";
		return false;
	}
	//打印fibon数列,1,1,2,3,5,8.....
	switch (pos)
	{
	default:
	case 2:
		cout << "1 ";
	case 1:
		cout << "1 ";
		break;
	}
	int elem;
	int n_1 = 1, n_2 = 1;
	for (int ix = 3; ix <= pos; ix++)
	{
		elem = n_1 + n_2;
		n_2 = n_1;
		n_1 = elem;
        //一行打印十个数,使用条件表达式
		cout << elem<<((ix % 10 == 0 )?"\n" : " ");
	}
	cout << endl;
	return true;
}

在主函数调用并且给出交互信息

cout << "the fibonacci sequence for " << pos << " positions:" << endl;
	print_elem(pos);

这时我们发现在打印函数中再一次出现了for循环重新计算Fibonacci数列,这个操作与我们的fibon_elem操作重复了,我们最好让一个函数实现一个功能,这样就不会让读代码的人感到困惑

想要实现这个功能,我们需要引入vector这个容器,不了解其用法的可以去看博主的vector用法详解

vector<int> elem_seq(int);
vector<int> elem_seq(int size)
{
	if (size <= 0 || size >= 1024)
	{
		cout << "warning:fibon_seq():"
			<< size << "not supported \n";
	}
	vector<int> elems(size);
	for (int ix = 0; ix < size; ++ix)
	{
		if (ix == 0 || ix == 1)
			elems[ix] = 1;
		else
			elems[ix] = elems[ix - 1] + elems[ix - 2];
	}
	return elems;
}

这是修改后的print_elem函数

bool print_elem(int pos)
{
	判断位置合法性
	if (pos <= 0 || pos >= 1024)
	{
		cout <<endl<< "invaild position: " << pos
			<< ",cannot handle the request";
		return false;
	}
    for (int ix = 0; ix < pos; ix++)
	    cout << seq[ix]<< (((ix+1) % 10 == 0) ? "\n" : " ");;
	return true;
}

如果用户先计算了位置为23的Fibonacci数,又想要接着计算26的Fibonacci数,根据先前的代码,我们需要计算两遍,有没有什么办法保留位置为23之前的Fibonacci数,只去计算23-26之间的数呢,这样我们代码的执行效率就得到了很大的提高

当然是有方法的(不然也不这么问了),引入一个新的知识:局部静态对象

局部对象会在函数结束是弃置,而局部静态对象的生存周期更长一些,当程序结束的时候,它的析构函数才被执行,单比全局对象的析构函数早一步,它位于数据段(静态区)中,即便在其他函数调用过程中,依然持续存在

 为了区分前面的函数,我们重新定义一个fibon_seq函数

const vector<int>*
fibon_seq(int size)
{
	const int max_size = 1024;
	static vector<int>elems;
	if (size <= 0 || size >= 1024)
	{
		cerr << "fibon_seq(): oops: invalid size: "
			<< size << "--can't fufill request.\n";
		return 0;
	}
	//如果size小于elems.size,就不需要计算了
	for (int ix = elems.size(); ix < size; ix++)
	{
		if (ix == 0 || ix == 1)
			elems.push_back(1);
		else
			elems.push_back(elems[ix - 1] + elems[ix - 2]);
	}
	cout << "The size is " << elems.size()<<endl;
	return &elems;
}

再定义一个fibon_elem2用来返回位置为pos的Fibonacci数

//返回位置为pos的元素
//pos-1,因为vector的起始元素位置为0
bool fibon_elem2(int pos, int& elem)
{
	const vector<int>* pseq = fibon_seq(pos);
	if (!pseq)
	{
		elem = 0;
		return false;
	}
	elem = (*pseq)[pos - 1];
	return true;
}

我们还需要更改一下主函数的代码,使用户可以选择继续计算Fibonacci数或者结束计算

#include<cstdlib>
int main()
{
	int pos = 0;
	int elem = 0;
	int choice = 1;
	while (choice)
	{
		cout << "Please enter a position:";
		cin >> pos;
		fibon_seq(pos);
		if (!fibon_elem(pos, elem))
			cout << "Sorry the position is inexistence";
		else
			cout << "The elemment " << pos << " is " << elem << endl;
		cout << "Whether you want to continue calculating"
			<< endl << "1.continue 2.exit" << endl;
		cin >> choice;
		switch (choice)
		{
		default:
		case 1:
			break;
		case 2:
			exit(-1);
			break;
		}
		return 0;
	}
}

感谢大家的阅读,感觉有帮助的话就三连支持一下博主吧

有不足还请指出,共同进步

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值