我相信每一个学过语言的人都应该知道斐波那契数列这么个东西。关于斐波那契数列我们也做过相关的题,接下来,我们来探讨一下这个问题。
面试题9:斐波那契数列
题目一:写一个函数,输入n,求斐波那契数列的第n项。斐波那契数列的定义如下:当n=0时,f(n)=0,当n=1时,f(n)=1,当n>1时,f(n)=f(n-1)+f(n-2)。
这个算法首先咱们应该知道,很多书会用递归的算法解决这个问题。
#include<stdio.h>
#include<stdlib.h>
long long fib(unsigned int n)
{
if (n == 1)
return 1;
else if (n <= 0)
return 0;
else
return fib(n - 1) + fib(n - 2); //递归,
}
int main()
{
unsigned int n = 0;
long long ret = 0;
printf("Please give the first few items:\n");
scanf("%u", &n);
ret = fib(n);
printf("%lld\n", ret);
system("pause");
return 0;
}
这就是递归的算法,我想在你的测试过程中你可能已经感受到了这种算法效率之差,虽然可以算出来结果,但是效率太低了,原因是在过程中每次运行时堆栈,频繁的函数调用,造成最后效率极为不佳,在这里我们要求f(4)就要求f(3)和f(2),求f(3)又要求(2)和f(1),最后这样一次求下去。在这里n会指数的方式进行递增。
在这的这种递归我们叫做尾递归,如果一个函数中所有递归形式的调用都出现在函数的末尾,我们称这个递归函数是尾递归的。当递归调用是整个函数体中最后执行的语句且它的返回值不属于表达式的一部分时,这个递归调用就是尾递归。尾递归函数的特点是在回归过程中不用做任何操作,这个特性很重要,因为大多数现代的编译器会利用这种特点自动生成优化的代码。
尾递归可以进行优化,下面就是我们要重点说的内容了,当我们遇到尾递归,我们可以采用迭代的方式进行优化,所谓迭代,简单说就是循环。
#include<stdio.h>
#include<stdlib.h>
long long fib(unsigned int n)
{
int ret[2] = { 0, 1 };
if (n < 2)
return ret[n];
long long fib1 = 1;
long long fib2 = 0;
long long fib = 0;
unsigned int i = 0;
for (i = 2; i <= n; ++i)
{
fib = fib1 + fib2;
fib2 = fib1;
fib1 = fib;
}
return fib;
}
int main()
{
unsigned int n = 0;
long long ret = 0;
while (1){
printf("Please give the first few items:\n");
scanf("%u", &n);
ret = fib(n);
printf("%lld\n", ret);
}
system("pause");
return 0;
}
这是书上所给的一种迭代的方法。
然后我自己又想到了一种方法。
#include<stdio.h>
#include<stdlib.h>
long long fib(unsigned int n)
{
long long fib1 = 1;
long long fib2 = 0;
unsigned int i = 0;
for (i = 0; i < n ; i++)
{
fib1 = fib1 + fib2;//在这里进行一个算法,首先fib1成了你给的前两个的和。并且赋给了第一个数,这里的第一项数就是下一次计算中的fib1。
fib2 = fib1 - fib2;//这里是对你所需要的数进行计算,在这里更新的fib1减去fib2就是新的第二项数
}
return fib2;
}
int main()
{
unsigned int n = 0;
long long ret = 0;
while (1){
printf("Please give the first few items:\n");
scanf("%u", &n);
ret = fib(n);
printf("%lld\n", ret);
}
system("pause");
return 0;
}