目录

1、斐波那契数列(Fibonacci)介绍

2、朴素递归算法(Naive recursive algorithm)

3、朴素递归平方算法(Naive recursive squaring)

4 、自底向上算法(Bottom-up)

5、 递归平方算法(Recursive squaring)

6、完整代码(c++)

7、参考资料

内容

1、斐波那契数列(Fibonacci)介绍

Fibonacci数列应该也算是耳熟能详,它的递归定义如上图所示。

下面2-6分别说明求取Fibonacci数列的4种方法

2、朴素递归算法(Naive recursive algorithm)

在很多C语言教科书中讲到递归函数的时候,都会用Fibonacci作为例子。因此很多程序员对这道题的递归解法非常熟悉,看到题目就能写出如下的递归求解的代码

  unsigned long long Fibonacci_naive_reu(int n)//朴素递归算法
{
int result[] = {,};
if (n<) //退出条件
return result[n]; return (Fibonacci_naive_reu(n-)+ Fibonacci_naive_reu(n-));//递归调用
}

其实这种想法很好,但该算法运行时间令人无法忍受,当计算n=50时,用时1200多秒

分析:该算法的时间复杂度T(n)=Θ(∂n),其中,∂ = (1 + 5^½) / 2,即黄金分割比率。可知,∂>1,随着n增加,时间指数快速增加,所以,平时很少采用!

3、朴素递归平方算法(Naive recursive squaring)

这个算法主要根据斐波那契数列的一条数学性质而来。该性质表明,斐波那契数列F(n)即为φ^n / 5^½向下取整。这样,问题的求解于是变成了一个求x的n次方的问题,在之前的文章里有讲解,链接请进。 所以算法的效率为Θ(lgn)。但是这个方法是不太靠谱的,主要是当n比较大时,由于硬件的限制计算机中的浮点运算得到的结果与真实值就产生误差了。实用价值也不大,只能用做理论分析。

4 、自底向上算法(Bottom-up)

考虑到2中的简单递归算法,为了求解F(n),需要同时递归求解F(n - 1)和F(n - 2),显然这样就做了大量的重复工作。采用自底向上的算法即可避免这样的冗余。要计算F(n),则依次计算F0,F1,F2。。。Fn,这时计算Fn只需要利用前两个结果即可,这样算法效率提高到了Θ(n)。n=50时,小于1毫秒。实用价值高。

算法代码:

  /************************************************************************/
/* 自底向上算法 */
// 时间复杂度T(n)=o(n)
/************************************************************************/
unsigned long long Fibonacci_bottom_up(int n)//自底向上算法
{
int result[] = {, };
if(n < )
return result[n]; unsigned long long fibNMinusN_1 = ;
unsigned long long fibNMinusN_2 = ;
unsigned long long fibN = ;
for(int i = ; i <= n; ++ i) //从底到上逐次计算出数列值
{
fibN = fibNMinusN_1 + fibNMinusN_2; fibNMinusN_2 = fibNMinusN_1;
fibNMinusN_1 = fibN;
} return fibN;//返回数组值
}

5、 递归平方算法(Recursive squaring)

上面的算法已经能达到Θ(n)线性效率,然而下面的这个算法能使效率达到T(n) = Θ(lgn)。该算法是基于一个定理,定理以及证明过程如下图所示。这样,问题的求解即成为了矩阵的乘方问题,算法效率于是提高到了Θ(lgn)。

矩阵求幂方法同常数求幂方法,采用分治思想,可参见常数求幂方法,下面是矩阵求幂实现代码:

 /************************************************************************/
/* 下面矩阵的n次幂,结果保存在 Result[2][2] */
// 矩阵的n次幂,采用分治法,与x的n 次方算法一致,时间复杂度T(n)=o(logn)
// 1 1
// 1 0
/************************************************************************/
void Matrix_power(int n,unsigned long long Result[][])//求矩阵幂
{
unsigned long long AResult[][];
unsigned long long zResult1[][];
unsigned long long zResult2[][]; AResult[][]=;AResult[][]=;AResult[][]=;AResult[][]=;
if (==n)
{
Result[][]=;Result[][]=;Result[][]=;Result[][]=;
}
else if (n%==)
{
Matrix_power(n/,zResult1);
MUL(zResult1,zResult1,Result);
}
else if (n% == )
{
Matrix_power((n-)/,zResult1);
MUL(zResult1,zResult1,zResult2);
MUL(zResult2,AResult,Result);
}
}

其中,两个矩阵相乘代码实现如下:

 /************************************************************************/
/* 两个 矩阵相乘 、结果矩阵保存在 MatrixResult[2][2]中 */
/************************************************************************/
void MUL( unsigned long long MatrixA[][],unsigned long long MatrixB[][], unsigned long long MatrixResult[][] )//矩阵相乘
{
for (int i=;i< ;i++)
{
for (int j=;j< ;j++)
{
MatrixResult[i][j]=;
for (int k=;k< ;k++)
{
MatrixResult[i][j]=MatrixResult[i][j]+MatrixA[i][k]*MatrixB[k][j];
}
}
}
}

6、完整代码(c++)

Fibonacci.h   其中递归平方法(矩阵求幂法)有两种实现,一种是我自己编码实现,另外是网上copy的代码。

 #ifndef FIBONACCI_HH
#define FIBONACCI_HH
struct Matrix2By2
{
Matrix2By2
(
unsigned long long m00 = ,
unsigned long long m01 = ,
unsigned long long m10 = ,
unsigned long long m11 =
)
:m_00(m00), m_01(m01), m_10(m10), m_11(m11)
{
} unsigned long long m_00;
unsigned long long m_01;
unsigned long long m_10;
unsigned long long m_11;
};
class Fibonacci
{
public:
unsigned long long Fibonacci_naive_reu(int n);//朴素递归算法
unsigned long long Fibonacci_bottom_up(int n);//自底向上算法
unsigned long long Fibonacci_recur_squar(int n);//递归平方算法
void MUL( unsigned long long MatrixA[][],unsigned long long MatrixB[][], unsigned long long MatrixResult[][] );
void Matrix_power(int n,unsigned long long result[][]); Matrix2By2 MatrixMultiply(const Matrix2By2& matrix1, const Matrix2By2& matrix2);
Matrix2By2 MatrixPower(unsigned int n);
unsigned long long Fibonacci_Solution3(unsigned int n); }; unsigned long long Fibonacci::Fibonacci_naive_reu(int n)//朴素递归算法
{
int result[] = {,};
if (n<) //退出条件
return result[n]; return (Fibonacci_naive_reu(n-)+ Fibonacci_naive_reu(n-));//递归调用
}
/************************************************************************/
/* 自底向上算法 */
// 时间复杂度T(n)=o(n)
/************************************************************************/
unsigned long long Fibonacci::Fibonacci_bottom_up(int n)//自底向上算法
{
int result[] = {, };
if(n < )
return result[n]; unsigned long long fibNMinusN_1 = ;
unsigned long long fibNMinusN_2 = ;
unsigned long long fibN = ;
for(int i = ; i <= n; ++ i) //从底到上逐次计算出数列值
{
fibN = fibNMinusN_1 + fibNMinusN_2; fibNMinusN_2 = fibNMinusN_1;
fibNMinusN_1 = fibN;
} return fibN;//返回数组值
}
/************************************************************************/
/* 两个 矩阵相乘 、结果矩阵保存在 MatrixResult[2][2]中 */
/************************************************************************/
void Fibonacci::MUL( unsigned long long MatrixA[][],unsigned long long MatrixB[][], unsigned long long MatrixResult[][] )//矩阵相乘
{
for (int i=;i< ;i++)
{
for (int j=;j< ;j++)
{
MatrixResult[i][j]=;
for (int k=;k< ;k++)
{
MatrixResult[i][j]=MatrixResult[i][j]+MatrixA[i][k]*MatrixB[k][j];
}
}
}
}
/************************************************************************/
/* 下面矩阵的n次幂,结果保存在 Result[2][2] */
// 矩阵的n次幂,采用分治法,与x的n 次方算法一致,时间复杂度T(n)=o(logn)
// 1 1
// 1 0
/************************************************************************/
void Fibonacci::Matrix_power(int n,unsigned long long Result[][])//求矩阵幂
{
unsigned long long AResult[][];
unsigned long long zResult1[][];
unsigned long long zResult2[][]; AResult[][]=;AResult[][]=;AResult[][]=;AResult[][]=;
if (==n)
{
Result[][]=;Result[][]=;Result[][]=;Result[][]=;
}
else if (n%==)
{
Matrix_power(n/,zResult1);
MUL(zResult1,zResult1,Result);
}
else if (n% == )
{
Matrix_power((n-)/,zResult1);
MUL(zResult1,zResult1,zResult2);
MUL(zResult2,AResult,Result);
}
}
unsigned long long Fibonacci::Fibonacci_recur_squar(int n)//递归平方算法
{
unsigned long long fib_result[][];
int result[] = {, };
if(n < )
return result[n];
Matrix_power(n,fib_result);
return fib_result[][];
} /************************************************************************/
/* 下面是网上copy的递归平方算法的代码 */
/************************************************************************/
///////////////////////////////////////////////////////////////////////
// Multiply two matrices
// Input: matrix1 - the first matrix
// matrix2 - the second matrix
//Output: the production of two matrices
///////////////////////////////////////////////////////////////////////
Matrix2By2 Fibonacci::MatrixMultiply
(
const Matrix2By2& matrix1,
const Matrix2By2& matrix2
)
{
return Matrix2By2(
matrix1.m_00 * matrix2.m_00 + matrix1.m_01 * matrix2.m_10,
matrix1.m_00 * matrix2.m_01 + matrix1.m_01 * matrix2.m_11,
matrix1.m_10 * matrix2.m_00 + matrix1.m_11 * matrix2.m_10,
matrix1.m_10 * matrix2.m_01 + matrix1.m_11 * matrix2.m_11);
} ///////////////////////////////////////////////////////////////////////
// The nth power of matrix
// 1 1
// 1 0
///////////////////////////////////////////////////////////////////////
Matrix2By2 Fibonacci::MatrixPower(unsigned int n)
{
Matrix2By2 matrix;
if(n == )
{
matrix = Matrix2By2(, , , );
}
else if(n % == )
{
matrix = MatrixPower(n / );
matrix = MatrixMultiply(matrix, matrix);
}
else if(n % == )
{
matrix = MatrixPower((n - ) / );
matrix = MatrixMultiply(matrix, matrix);
matrix = MatrixMultiply(matrix, Matrix2By2(, , , ));
} return matrix;
}
///////////////////////////////////////////////////////////////////////
// Calculate the nth item of Fibonacci Series using devide and conquer
///////////////////////////////////////////////////////////////////////
unsigned long long Fibonacci::Fibonacci_Solution3(unsigned int n)
{
int result[] = {, };
if(n < )
return result[n]; Matrix2By2 PowerNMinus2 = MatrixPower(n - );
return PowerNMinus2.m_00;
}
#endif

Fibonacci.h

Fibonacci.cpp (主函数)

 #include <iostream>
#include <vector>
#include <ctime>
using namespace std;
#include "Fibonacci.h" int main()
{
Fibonacci fib;
clock_t startTime_For_Fibonacci_naive_reu ;
clock_t endTime_For_Fibonacci_naive_reu ;
clock_t startTime_For_Fibonacci_bottom_up ;
clock_t endTime_For_Fibonacci_bottom_up ;
clock_t startTime_For_Fibonacci_recur_squar1 ;
clock_t endTime_For_Fibonacci_recur_squar1 ;
clock_t startTime_For_Fibonacci_recur_squar2 ;
clock_t endTime_For_Fibonacci_recur_squar2 ; startTime_For_Fibonacci_naive_reu=clock();
cout<<fib.Fibonacci_naive_reu()<<endl;//朴素递归算法
endTime_For_Fibonacci_naive_reu=clock(); startTime_For_Fibonacci_bottom_up=clock();
cout<<fib.Fibonacci_bottom_up()<<endl;//自底向上算法
endTime_For_Fibonacci_bottom_up=clock(); startTime_For_Fibonacci_recur_squar1=clock();
cout<<fib.Fibonacci_recur_squar()<<endl;//我自己编写的递归平方算法
endTime_For_Fibonacci_recur_squar1=clock(); startTime_For_Fibonacci_recur_squar2=clock();
cout<<fib.Fibonacci_Solution3()<<endl;//网上copy的递归平方算法
endTime_For_Fibonacci_recur_squar2=clock(); cout<<"朴素递归算法用时: "<<(endTime_For_Fibonacci_naive_reu-startTime_For_Fibonacci_naive_reu)/(1.0*CLOCKS_PER_SEC)<<"秒"<<endl;
cout<<"自底向上算法用时: "<<(endTime_For_Fibonacci_bottom_up-startTime_For_Fibonacci_bottom_up)/(1.0*CLOCKS_PER_SEC)<<"秒"<<endl;
cout<<"我自己编写的递归平方算法用时: "<<(endTime_For_Fibonacci_recur_squar1-startTime_For_Fibonacci_recur_squar1)/(1.0*CLOCKS_PER_SEC)<<"秒"<<endl;
cout<<"网上copy的递归平方算法用时: "<<(endTime_For_Fibonacci_recur_squar2-startTime_For_Fibonacci_recur_squar2)/(1.0*CLOCKS_PER_SEC)<<"秒"<<endl;
system("Pause");
return ;
}

输出:

结:朴素递归算法用时太多,实用价值不大,自底向上算法效率为线性,较高,平时用较多,递归平方算法效率为对数级,且编程可实现,实用价值很大。并且经过测试,当n值变很大后,递归平方算法效率明显高于自底向上算法效率。

7、参考资料

【1】http://zhedahht.blog.163.com/blog/static/25411174200722991933440/

【2】http://blog.csdn.net/xyd0512/article/details/8220506

算法导论-求(Fibonacci)斐波那契数列算法对比的更多相关文章

  1. Python算法_三种斐波那契数列算法

    斐波那契数列(Fibonacci sequence),又称黄金分割数列.因数学家列昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为"兔子数列&qu ...

  2. 算法 递归 迭代 动态规划 斐波那契数列 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  3. 递归算法之Fibonacci 斐波那契数列第n个数的求解

    Fibonacci 斐波那契数列第n个数的求解,也可以用递归和非递归的形式实现,具体如下,dart语言实现. int fibonacci(int n) { if (n <= 0) throw S ...

  4. 《BI那点儿事》Microsoft 时序算法——验证神奇的斐波那契数列

    斐波那契数列指的是这样一个数列 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,377,610,987,1597,2584,4181,6765,10 ...

  5. lintcode:Fibonacci 斐波纳契数列

    题目: 斐波纳契数列 查找斐波纳契数列中第 N 个数. 所谓的斐波纳契数列是指: 前2个数是 0 和 1 . 第 i 个数是第 i-1 个数和第i-2 个数的和. 斐波纳契数列的前10个数字是: 0, ...

  6. 【算法】php实现斐波那契数列

    斐波那契数列指的是这样一个数列 1, 1, 2, 3, 5, 8, 13, 21.这个数列从第3项开始,每一项都等于前两项之和. 根据这个定义,斐波那契数列的递推公式是:f(n)=f(n-1)+f(n ...

  7. 基于visual Studio2013解决算法导论之045斐波那契堆

     题目 斐波那契堆 解决代码及点评 // 斐波那契堆.cpp : 定义控制台应用程序的入口点. // #include<iostream> #include<cstdio> ...

  8. Fibonacci(斐波那契数列)的最佳实践方式(JavaScript)

    1)低级版本 var fibonacci = function(n) { if (n == 0 || n == 1) { return n; } else { return fibonacci(n - ...

  9. fibonacci 斐波那契数列

    1.小兔子繁殖问题  (有该问题的详细来由介绍) 2.台阶问题 题目:一个人上台阶可以一次上一个或者两个,问这个人上n层的台阶,一共有多少种走法. 递归的思路设计模型: i(台阶阶数)         ...

随机推荐

  1. redis配置错误导致服务器不能启动

    redis-server忘了把配置里面的daemonize的no改成yes所以把redis-server加入到了/etc/rc.local里面,在服务器启动的时候就会阻塞在这里,导致服务器不能启动.[ ...

  2. JavaScript设置获取和设置属性的方法

    这篇文章主要介绍了JavaScript设置获取和设置属性的方法,学会使用getAttribute.setAttribute的用法,需要的朋友可以参考下   getAttribute 该方法用来获取元素 ...

  3. 安全测试===BurpSuite使用教程-附安装包

    jar包: Burpsuite1.6亲测可用.zip 我的jdk版本: 运行包: >>> java -cp BurpLoader.jar;burpsuite_pro_v1.6.jar ...

  4. python基础===文件对象的访问模式,以及计数循环的使用方法

    案例一: 一个几M的文本文件,需要每隔100行写到新的文件中. 代码实现如下: with open(r'f:\book.txt','rb') as f1: with open(r'f:\book2.t ...

  5. 【反演复习计划】【51nod1594】Gcd and Phi

    现在感觉反演好多都是套路QAQ…… #include<bits/stdc++.h> using namespace std; ; typedef long long ll; int n,c ...

  6. centos6.5 挂载远程目录

    查看nfs程序是否安装: [root@crawler_mv02 ~]# rpm -qa |grep rpcbindrpcbind-0.2.0-13.el6_9.1.x86_64[root@crawle ...

  7. 使用 .NET Core 的日志记录

    如何使用 Microsoft.Extensions.Logging   public static void Main(string[] args = null) {  ILoggerFactory ...

  8. OC学习——OC中的@protocol(@required、@optional)、代理设计模式

    一.什么是协议? 1.协议声明了可以被任何类实现的方法   2.协议不是类,它是定义了一个其他对象可以实现的接口   3.如果在某个类中实现了协议中的某个方法,也就是这个类实现了那个协议.   4.协 ...

  9. selenium+python自动化81-html报告优化(饼图+失败重跑+兼容python2&3)【转载】

    优化html报告 为了满足小伙伴的各种变态需求,为了装逼提升逼格,为了让报告更加高大上,测试报告做了以下优化: 测试报告中文显示,优化一些断言失败正文乱码问题 新增错误和失败截图,展示到html报告里 ...

  10. poj 1066(枚举+线段相交)

    Treasure Hunt Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 6328   Accepted: 2627 Des ...