Fibonacci数——求第n个斐波拉契数

来源:互联网 发布:最佳作息时间 知乎 编辑:程序博客网 时间:2024/05/22 15:33

Fibonacci数——求第n个斐波拉契数

#include<iostream>#include<cmath>#include<ctime>using namespace std;time_t begin_,end_;//递归版本一long Fibonacci_rec_v1(long const n){    if (n == 1 || n == 2) return 1L;    return Fibonacci_rec_v1(n-1) + Fibonacci_rec_v1(n-2);}//递归版本二 动态规划long *FibonacciNum;bool *isdone;long Fibonacci_rec_v2(long const n){    if (isdone[n]) return FibonacciNum[n];    isdone[n] = true;    FibonacciNum[n] = Fibonacci_rec_v2(n - 1) + Fibonacci_rec_v2(n - 2);    return FibonacciNum[n]; }//非递归版本一long Fibonacci_norec_v1(long const n){    long fnmins1(1l);    long fnmins2(1l);    long temp;    for (int i(2); i < n; i++){        temp = fnmins1;        fnmins1 += fnmins2;        fnmins2 = temp;    }    return fnmins1;}//递归求乘方void _2x2MatrixCalc(long const a11, long const a12,                    long const a21, long const a22,                    long const c11, long const c12,                    long const c21, long const c22,                    long &b11, long &b12, long &b21, long &b22){    b11 = a11*c11 + a12*c21;    b12 = a11*c12 + a12*c22;    b21 = a21*c11 + a22*c21;    b22 = a21*c12 + a22*c22;}//求乘方问题void M_helper(long const, long const, long const, long const,              long &b11, long &b12, long &b21, long &b22,              long const n){    if (n == 1){ b11 = 1, b12 = 1; b21 = 1, b22 = 0; return; }    if (n % 2 == 0) {        M_helper(1, 1, 1, 0, b11, b12, b21, b22, n >> 1);        long t11(b11), t12(b12), t21(b21), t22(b22);        _2x2MatrixCalc (t11, t12, t21, t22,                        t11, t12, t21, t22,                        b11, b12, b21, b22                        );        return;    }    M_helper(1, 1, 1, 0, b11, b12, b21, b22, n >> 1);    long t11(b11), t12(b12), t21(b21), t22(b22);    _2x2MatrixCalc (t11, t12, t21, t22,                    t11, t12, t21, t22,                    b11, b12, b21, b22                    );    t11 = b11, t12 = b12, t21 = b21, t22 = b22;    _2x2MatrixCalc (1, 1, 1, 0,                    t11, t12, t21, t22,                    b11, b12, b21, b22                    );}//非递归版本二long Fibonacci_norec_v2(long const n){    long b11, b12, b21, b22;    M_helper(1,1,1,0,b11, b12, b21, b22,n-2);    return b11+b12;}//非递归版本三---存在精度问题。long Fibonacci_norec_v3(long const n){    double r1 = (1 - sqrt(5))/2;    double r2 = (1 + sqrt(5))/2;    return  (pow(r2, n - 1) + pow(r2, n - 2) - pow(r1, n - 1) - pow(r1, n - 2)) / (r2 - r1);}int main(){    long n;    cout << "输入序数"<<endl;    cin >> n;    begin_ = clock();    cout<<"Fibonacci_rec_v1结果:"<<Fibonacci_rec_v1(n)<<endl;    end_ = clock();    cout << "time:" << (double)(end_ - begin_) << "miliseconds"<<endl;    begin_ = clock();    FibonacciNum = new long[n+1];    isdone = new bool[n+1];    FibonacciNum[1] = 1; FibonacciNum[2] = 1;    for (int i(3); i <= n; i++)isdone[i] = false;    cout << "Fibonacci_rec_v2结果:" << Fibonacci_rec_v2(n) << endl;    end_ = clock();    cout << "time:" << (double)(end_ - begin_) << "miliseconds" << endl;    begin_ = clock();    cout << "Fibonacci_norec_v1结果:" << Fibonacci_norec_v1(n) << endl;    end_ = clock();    cout << "time:" << (double)(end_ - begin_) << "miliseconds" << endl;    begin_ = clock();    cout << "Fibonacci_norec_v2结果:" << Fibonacci_norec_v2(n) << endl;    end_ = clock();    cout << "time:" << (double)(end_ - begin_) << "miliseconds" << endl;    begin_ = clock();    cout << "Fibonacci_norec_v3结果:" << Fibonacci_norec_v3(n) << endl;    end_ = clock();    cout << "time:" << (double)(end_ - begin_) << "miliseconds" << endl;    system("pause");}

算法说明:

//递归版本一long Fibonacci_rec_v1(long const n){    if (n == 1 || n == 2) return 1L;    return Fibonacci_rec_v1(n-1) + Fibonacci_rec_v1(n-2);}

这个版本直接由Fibonacci的定义得到,重复计算的子问题比较多,效率非常低。

//递归版本二 动态规划long *FibonacciNum;bool *isdone;long Fibonacci_rec_v2(long const n){    if (isdone[n]) return FibonacciNum[n];    isdone[n] = true;    FibonacciNum[n] = Fibonacci_rec_v2(n - 1) + Fibonacci_rec_v2(n - 2);    return FibonacciNum[n]; }

这个版本是对上面那个版本的改进,用一对数组记录已经计算过了的子问题,这样就大大加快了算法的效率。

//非递归版本一long Fibonacci_norec_v1(long const n){    long fnmins1(1l);    long fnmins2(1l);    long temp;    for (int i(2); i < n; i++){        temp = fnmins1;        fnmins1 += fnmins2;        fnmins2 = temp;    }    return fnmins1;}

fn=fn1+fn2,可以由这个公式,迭代的自低向上找到fn,通过子问题累计到问题的解,没有重复计算的子问题,效率非常高。

//非递归版本二long Fibonacci_norec_v2(long const n){    long b11, b12, b21, b22;    M_helper(1,1,1,0,b11, b12, b21, b22,n-2);    return b11+b12;}

由公式fn=fn1+fn2,可得下面的矩阵方程:

(fnfn1)=(1110)(fn1fn2)
这个矩阵方程可以化为
(fnfn1)=(1110)n2(11)
M
(1110)n2
,整个找第n个Fibonacci数的算法就转化为了求矩阵M。找M的算法就和数值自乘方求解的问题如出一辙,可以用递归的算法实现,还可以在递归的基础上用动态规划的方法提高求解效率,更可以用迭代的方式来求解。

//非递归版本三---存在精度问题。long Fibonacci_norec_v3(long const n){    double r1 = (1 - sqrt(5))/2;    double r2 = (1 + sqrt(5))/2;    return  (pow(r2, n - 1) + pow(r2, n - 2) - pow(r1, n - 1) - pow(r1, n - 2)) / (r2 - r1);}

可以根据矩阵对角化的公式A=PDP1(其中D是对角矩阵)将A:

(1110)
对角化然后直接求解。An=PDnP1。最后得到fn=rn12+rn22rn11rn21r2r1r1,r2A

0 0
原创粉丝点击