算法设计与分析——分治算法-计算Fibonacci数列

                             分治算法-计算Fibonacci数列

  • 实验目的

通过朴素递归算法、自底向上算法和分治算法的比较理解如何利用分支思想设计一个高效算法。

  • 实验内容
  1. 编写函数实现用朴素递归算法计算Fibonacci数列;
  2. 编写函数实现用自底向上算法计算Fibonacci数列;
  3. 编写函数实现用分治算法计算Fibonacci数列;
  4. 测试n取10、40、45、50的情况下三种算法各自的运行时间,通过对比分析研究哪个算法在数据量逐渐增大时效率高;
  5. 对三种算法进行理论分析哪个算法效率高;
  6. 与实验数据对照,检查是否实验结果验证了理论分析的结果。
  7. 当n取50时运行结果是怎样的,分析结果异常的原因。
  • 算法伪代码

朴素递归算法伪代码:

 Simple(n)

    if  n =0

            return 0

    if  n == 1 || n == 2

        return 1

    return Simple(n -1)+Simple(n - 2)

自底向上算法伪代码:

 Down_To_Up(n)

    if n =0

        return 0

    else if n == 1 || n == 2

        return 1

    else

        f[0] = 0

        f[1] = 1

        f[2] = 1

        for  i = 3 to n

        f[i] = f[i - 1] + f[i - 2]

     return f[n]

分治算法伪代码:

Divide_Conquer( A, n)

{

     w= {1,0,0,1}

    q=w

    if  n = 0

        return q

    else if  n =1

        return A

    else if  n%2=0

        return one(Divide_Conquer(A, n / 2), Divide_Conquer(A, n / 2))

    else

        return one(one(Divide_Conquer(A, (n - 1) / 2), Divide_Conquer(A, (n - 1) / 2)), A)

 

 

  • 理论分析

    朴素递归算法为Θ(φ^n)时间复杂度,自底向上算法为Θ(n)时间复杂度,分治算法为Θ(lgn)时间复杂度。自底向上算法的时间复杂度分治算法的时间复杂度<朴素算法的时间复杂度。由于斐波那契序列随着项数增加,使用递归调用时前四十项求解没有问题,但五十项及以后的时候会出现内存溢出,输出为错误结果。所以要想求出更多的项必须使用非递归的方法求解。

  • 测试用例
  • 性能测试
  • 测试结果示例:(单位:微秒)

     

     

    算法名称

    运行时间

    数据量

    10

    40

    45

    50

    平均运行时间

    朴素递归算法

    1

    904722

    1.02134e+007

    1.4857e+008

    Θ(φ^n)

    自底向上算法

    0.3

    0.3

    0.4

    0.9

    Θ(n)

    分治算法

    1.7

    4.9

    5.2

    13.1

    Θ(lgn)

    源代码

  • #include <iostream>
    #include<algorithm>
    #include<cstdio>
    #include<set>
    #include<windows.h>
    const int INF = 1e8;
    typedef long long ll;
    using namespace std;
    struct node
    {
        ll m[2][2];
    };
    node A = { 1, 1, 1, 0 };
    node one(node a,node b)
    {
        node c;
        ll i, j, k;
        for (i = 0; i < 2; i++)
        {
            for (j = 0; j < 2; j++)
            {
                c.m[i][j] = 0;
                for (k = 0; k <= 1; k++)
                {
                    c.m[i][j] += a.m[i][k] * b.m[k][j];
                }
            }
        }
        return c;
    }
    /*朴素算法*/
    int Simple(ll n)
    {
        if(n == 0)
        {
            return 0;
        }
        if(n == 1 || n == 2)
        {
            return 1;
        }
        return Simple(n -1)+Simple(n - 2);
    }
    /*分治算法*/
    node  Divide_Conquer(node A, ll n)
    {
        node q,w;
        w= {1,0,0,1};
        q=w;
        if (n == 0)
            return q;
        else if (n == 1)
            return A;
        else if (n%2==0)
            return one(Divide_Conquer(A, n / 2), Divide_Conquer(A, n / 2));
        else
            return one(one(Divide_Conquer(A, (n - 1) / 2), Divide_Conquer(A, (n - 1) / 2)), A);
    }
    /*自底向上算法*/
    int Down_To_Up(ll n)
    {
        if(n == 0)
        {
            return 0;
        }
        else if(n == 1 || n == 2)
        {
            return 1;
        }
        else
        {
            ll f[n + 1]; //f
            f[0] = 0;
            f[1] = 1;
            f[2] = 1;
            for(ll i = 3; i <= n; i++)
            {
                f[i] = f[i - 1] + f[i - 2];
            }
            return f[n];
        }
    }
    int main()
    {
        ios::sync_with_stdio(false);//C++为了兼容C而采取的保守措施
        cin.tie(0), cout.tie(0);//减少cin,cout时间
        ll n;
        while(~scanf("%lld",&n))
        {
            double run_time;
            _LARGE_INTEGER time_start;  //开始时间
            _LARGE_INTEGER time_over;   //结束时间
            double dqFreq;              //计时器频率
            LARGE_INTEGER f;            //计时器频率
            QueryPerformanceFrequency(&f);
            dqFreq = (double)f.QuadPart;
            /*朴素算法*/
            QueryPerformanceCounter(&time_start);   //计时开始
            ll ans1 =Simple(n);
            QueryPerformanceCounter(&time_over);    //计时结束
            run_time = 1000000 * (time_over.QuadPart - time_start.QuadPart) / dqFreq;//乘以1000000把单位由秒化为微秒,精度为1000 000/(cpu主频)微秒
            cout << "朴素算法时间: " << run_time << endl;
            cout << "朴素算法结果: " << ans1 << endl;
            /*自底向上算法*/
            QueryPerformanceCounter(&time_start);   //计时开始
            ll ans2 =Down_To_Up(n);
            QueryPerformanceCounter(&time_over);    //计时结束
            run_time = 1000000 * (time_over.QuadPart - time_start.QuadPart) / dqFreq;//乘以1000000把单位由秒化为微秒,精度为1000 000/(cpu主频)微秒
            cout << "自底向上时间: " << run_time << endl;
            cout << "自底向上结果: " << ans2 << endl;
            /*分治算法*/
            QueryPerformanceCounter(&time_start);   //计时开始
            node a= Divide_Conquer(A, n - 1);
            QueryPerformanceCounter(&time_over);    //计时结束
            run_time = 1000000 * (time_over.QuadPart - time_start.QuadPart) / dqFreq;//乘以1000000把单位由秒化为微秒,精度为1000 000/(cpu主频)微秒
            cout << "分治算法时间: " << run_time << endl;
            cout << "分治算法结果: " << a.m[0][0]  << endl;
        }
         return 0;
    }
    

     

  • 3
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值