首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

【转】三种方法求解Fibonacci(斐波那契据)数列:递归法、迭代法、通项公式法

2012-12-23 
【转】三种方法求解Fibonacci(斐波那契)数列:递归法、迭代法、通项公式法所谓Fibonacci数列是指这样一种数列,

【转】三种方法求解Fibonacci(斐波那契)数列:递归法、迭代法、通项公式法

所谓Fibonacci数列是指这样一种数列,它的前两项均为1,从第三项开始各项均为前两项之和。用数学公式表示出来就是:
?????????? 1??????????????????????????? (n=1,2)
fib(n)=
?????????? fib(n-1)+fib(n-2)???? (n>2)
可以证明斐波那契数列的通项公式为fib(n) = [(1+√5)/2]^n /√5 - [(1-√5)/2]^n /√5 (n=1,2,3.....),关于斐波那契数列的详细介绍请参阅百度百科。
下面我将介绍三种比较常用的求解第n项斐波那契数列的方法:递归法、迭代法、通项公式法。
1、递归法
这种方法的优点是简洁和容易理解,缺点是时间复杂度太大,随着n的增大,运算时间将会急剧增加。因此在很多场合这种方法是不可取的。
使用这种方法的关键代码是:
if(n == 1|| n== 2)
{
??? return 1;
}
else
{
??? return fib(n - 1) + fib(n - 2);
}
2、迭代法
这种方法相对于递归法来说在时间复杂度上减小了不少,但代码相对就要复杂些了。它的思想是这样的,假设开始时f0=1,f1=1,currentFib表示当前斐波那契数,则:
for(i = 1;i < n;i++)
{
??? currentFib = f0 + f1;
??? f0 = f1;
??? f1 = currentFib;
}
这样迭代结束和currentFib就是fib(n)了。
3、通项公式法
这种方法是最没技术含量的方法,只要你知道通项公式照着把它翻译成编程语言就可以了,优点不言而喻。
fib(n) = pow(((1 + sqrt(5)) / 2.0),n) / sqrt(5) - pow(((1 - sqrt(5)) / 2.0),n) / sqrt(5));
小结:
这三种方法各有优缺点,使用哪种方法根据实际情况确定,从时间复杂度上来说O(通向公式法)<O(迭代法)<O(递归法)。
下面我做了一个简单的测试:分别测试这三种方法计算0-30这31个斐波那契数所用的总时间。从测试结果看,递归确实很费时,特别是n在30以后计算起来就很费时了,而另外两种方法计算这31个斐波那契数所费时间基本为0。当然结果不会很准确,但至少能说明问题。
测试代码:
************************************************************************************************************************************
#include <stdio.h>
#include <math.h>
#include <time.h>
#define ROOT_OF_FIVE sqrt(5.0)
long double fib1(int n);
//使用递归
long double fib2(int n);
//使用迭代
long double fib3(int n);
//使用通项公式
int main()
{
??? int i;
??? long double result1[31],result2[31],result3[31],consume[3],start,finish;
??? printf("N?????????? 递归法????????? 迭代法????????? 通项公式法\n");
???
??? start = (long double)clock();
??? for(i = 0;i <= 30;i++)
??? {???
??? ??? result1[i] = fib1(i);
??? }
??? finish = (long double)clock();
??? consume[0] = finish - start;

??? start = (long double)clock();
??? for(i = 0;i <= 30;i++)
??? {???
??? ??? result2[i] = fib2(i);
??? }
??? finish = (long double)clock();
??? consume[1] = finish - start;

??? start = (long double)clock();
??? for(i = 0;i <= 30;i++)
??? {???
??? ??? result3[i] = fib3(i);
??? }
??? finish = (long double)clock();
??? consume[2] = finish - start;

??? for(i = 0;i <= 30;i++)
??? {
??? ??? printf("%02d????????? %06.0lf????????? %06.0lf????????? %06.0lf\n",i,result1[i],result2[i],result3[i]);
??? }
??? printf("Total time: %lfms??? %lfms????? %lfms\n",consume[0],consume[1],consume[2]);
??? return 0;
}

long double fib1(int n)
{//使用递归
??? if(n == 0)
??? {
??? ??? return 0;
??? }
??? else if(n == 1)
??? {
??? ??? return 1;
??? }
??? else
??? {
??? ??? return fib1(n - 1) + fib1(n - 2);
??? }
}

long double fib2(int n)
{//使用迭代
??? if(n == 0)
??? {
??? ??? return 0;
??? }
??? else if(n == 1)
??? {
??? ??? return 1;
??? }
??? else
??? {
??? ??? long double f0 = 0,f1 = 1,currentFib;
??? ??? int i;
??? ??? for(i = 1;i < n;i++)
??? ??? {
??? ??? ??? currentFib = f0 + f1;
??? ??? ??? f0 = f1;
??? ??? ??? f1 = currentFib;
??? ??? }
??? ??? return currentFib;
??? }
}

long double fib3(int n)
{//使用通项公式Fib(n) = [(1+√5)/2]^n /√5 - [(1-√5)/2]^n /√5
??? return (pow(((1 + ROOT_OF_FIVE) / 2.0),n) / ROOT_OF_FIVE -
??? ??? pow(((1 - ROOT_OF_FIVE) / 2.0),n) / ROOT_OF_FIVE);
}


转自http://hi.baidu.com/aleczhou/blog/item/9208f103533eb8723812bb35.html

热点排行