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;
}
}
感谢大家的阅读,感觉有帮助的话就三连支持一下博主吧
有不足还请指出,共同进步