zoukankan      html  css  js  c++  java
  • Fibonacci数

    斐波那契数列(Fibonacci Sequence)

    又称黄金分割数列,或兔子数列(因为是斐波那契观察兔子生殖而总结得到)。

    在数学上,被定义为递推式:F(1)=1, F(2)=1, F(3)=2, F(4)=3, F(5)=5, ..., F(n)=F(n-1)+F(n-2)(n≥3)


     单元测试

    #include <stdio.h>
    #include <time.h>
    
    int R[1000]={0};
    
    int main(void){
        int N = 50;
    //    int N = 1e6;
        double start, finish;
        
        start = clock();
        printf("%lld
    ", fib(N));
        finish = clock();
        
        printf("%f s", (finish-start)/CLOCKS_PER_SEC);
        
        return 0;
    } 

    递归实现

    根据它的递推表达式,很容易想到使用递归实现。

    版本A:

    1 int fib_A(int N){
    2     if( N <= 2 )
    3       return 1;
    4     int tmp = fib_A(N-1)+fib_A(N-2);
    5     printf("%d: %d
    ", N, tmp);
    6     return tmp;
    7 }

    代码很简单,但是计算很慢!算前50个Fibonacci数需要超过60秒。分析算法,发现很多实例在进行重复计算!

    如此,根据这一点很容易想到使用查表的形式进行改进。

    版本B:

     1 long long fib_B(int N, long long* A){
     2     if( A[N] != 0 )//A已初始化为0
     3       return A[N];
     4       
     5     A[N] = fib_B(N-1, A)+fib_B(N-2, A);
     6     if( R[N] == 0 ){
     7         printf("%d: %lld
    ", N, A[N]);
     8         R[N] = 1;
     9     } 
    10     return A[N];
    11 }

    从结果看,仅算前50个改进明显,事实测试中算前10000个数压力都不大(不超过1s)。可以证明得到比较好的改进。


    迭代

    递归是一种自上而下的算法思路,因此为了计算n,会保留n(压栈)去结算n-1,以此类推,直到碰到递归基,占内存较大(O(n))。而迭代是自下而上,如果能得到迭代表达式,计算应该是非常快且不占空间的(O(1))。

    Fibonacci递推式:F(n)=F(n-1)+F(n-2)。可知当前F(n)的结果需要根据前两项得到,因此我们可以使用两个变量,一直保存前两项的值,每次迭代都更新这两项,一直跌到到需要计算的n。

     1 long long fib_itera(int N){
     2     int i; 
     3     long long f, g;
     4     
     5     f = 1; g = 1;//第1项、第2项的值
     6     for( i=3; i<=N; i++){
     7         f = f + g;
     8         g = f - g;
     9         printf("%d: %lld
    ", i, f);
    10     } 
    11     return f;
    12 } 

    运行速度是跟之前的递归B版本差不多。


    Fibonacci数应用

    Fibonacci数不仅仅只是在学习递归的时候可以用到,实际中应该是很广泛的。这里举两个例子。

    1. Fibonacci查找

    是对二分查找的longN的常系数进行改进,可以通过严格的证明,使用Fibonacci黄金分割在查找时对数列进行分割会得到最优的常系数。具体实现与证明与在查找篇给出,这里暂不提。

    2. 爬楼梯

    也是比较常见的一种面试题:如果每次爬楼梯只能一次跨一个或两个台阶,那么到第n个台阶有多少中走法?语义规定地面算第0个台阶。

    第一层台阶:F(1) = 1; 第二层台阶:可以一步一步,也可以一次两步,F(2) = 2;第三层台阶:可以1、1、1,或1、2,或2、1,F(3) = 3;第四层:1、1、1、1,或1、1、2,或1、2、1,或2、1、1,或2、2,F(4) = 5。

    得到递推式,F(1) = 1,F(2) = 2,F(n) = F(n-1) + F(n-2)(n>2)。

    同理,如果一次可以跨1、2、3个台阶,也一样可以先推理出前几项的值,然后得到递推表达式(变形的Fibonacci数列)。

  • 相关阅读:
    psy & vr
    psy 2
    psy
    linux c中select使用技巧
    hostent h_addr_list
    gethostbyname() -- 用域名或主机名获取IP地址
    c_select 调用参数说明
    [NYOJ 737] 石子合并(一)
    [HDU 1059] Dividing
    [HDU 1789] Doing Homework again
  • 原文地址:https://www.cnblogs.com/EasonDongH/p/9577001.html
Copyright © 2011-2022 走看看