zoukankan      html  css  js  c++  java
  • 《数据结构与算法分析》学习笔记(二)——算法分析

    一、对算法分析方法的最简单的理解和使用方法

    1、首先大家可能一般会被那些数学的概念搞晕,其实简单理解下来,就是假设任何语句执行的效率都是一样的,所以设定每一个语句的执行时间都是一个时间单位,那么只要计算这个程序到底执行了多少语句,就可以算出其时间复杂度。

    2、其次就是我们要明白,我们是个估算,所以可以进行化简,明显我们可以忽略那些相对来说低阶的项,只分洗最高阶项。然后主要就是有这些常见的法则:

    (1)FOR循环

    一次for循环的运行时间至多是该for循环内语句的运行时间乘以迭代次数。

    (2)嵌套的FOR循环

    肯定是计算最内层循环语句的执行次数,然后再乘以所以循环的迭代次数。

    (3)整个程序

    其实找到循环迭代次数最多,嵌套最多的进行计算就好。

    3、当然,我们计算的只是大概值,而且为了计算的简便,我们一边进行适当的放大,即只考虑最坏最坏的情况,算出其时间复杂度即可。

    二、最大子序列

    书中通过4种不同的解法来进一步强化我们应该如何计算时间复杂度,小白我也好好学习了下,在此写下学习笔记。

    题目:算出一个整数序列中最大的子序列的值。

    算法一:

    int MaxSubsequenceSum1(const int A[],int N)

    {

    int thisSum , MaxSum;

    MaxSum=0;

    for (int i =0; i<N; i++)

    {

    for (int j=i; j<N; j++)

    {

    thisSum=0;

    for (int K =i; K<=j; K++)

    {

    thisSum+=A[K];

    }

    if(thisSum>MaxSum)

    {

    MaxSum=thisSum;

    }

    }

    }

      

    if(MaxSum==0)

    {

    int i;

    for(i=0;i<N;i++)

    {

    if(A[i]!=0)

    break;

    }

    if(i!=N)

    {

    int Max=A[0];

    for(int j=0;j<N;j++)

    {

    if(A[j]>Max)

    {

    Max=A[j];

    }

    }

    MaxSum=Max;

      

    }

    }

     

      

      

    return MaxSum;

      

     

    }


    我们可以看出其最大的for循环有三重,而且最坏的可能迭代次数都是N,所以我们可以很容易的得出,此算法的时间复杂度为O(N^3),其中资源最明显的浪费就在重复计算了从低i到第k的子序列的值,所以算法二便是进行了简单的修改。
    算法二:

    int MaxSubsequenceSum2(const int A[],int N)

    {

    int thisSum,MaxSum;

    MaxSum=0;

    for (int i=0; i<N; i++)

    {

    thisSum=0;

    for (int j=i; j<N; j++)

    {

    thisSum+=A[j];

    if(thisSum>MaxSum)

    {

    MaxSum=thisSum;

    }

    }

    }

      

      

    if(MaxSum==0)

    {

    int i;

    for(i=0;i<N;i++)

    {

    if(A[i]!=0)

    break;

    }

    if(i!=N)

    {

    int Max=A[0];

    for(int j=0;j<N;j++)

    {

    if(A[j]>Max)

    {

    Max=A[j];

    }

    }

    MaxSum=Max;

      

    }

    }

      

      

    return MaxSum;

     

     

    }


    其实改变的地方即使采用的累加的策略而已,但却使效率大大的提高了,所以这里也是提高算法效率的一个小小的技巧,即尽力减少不必要的计算,尽量利用现有的计算结果。
    算法三:

    int Max3(const int a,const int b,const int c)

    {

    int temp = (a>b)?a:b;

    temp=(temp>c)?temp:c;

    return temp;

    }

     

     

     

    int MaxSubSum(const int A[],int Left,int Right)

    {

    int MaxLeftSum,MaxRightSum;

    int MaxLeftBorderSum,MaxRightBorderSum;

    int LeftBorderSum,RightBorderSum;

      

    if(Left==Right)

    {

    if(A[Left]>0)

    return A[Left];

    else

    return 0;

    }

      

    int center=(Right+Left)/2;

      

    MaxLeftSum=MaxSubSum(A, Left, center);

    MaxRightSum=MaxSubSum(A, center+1, Right);

      

    LeftBorderSum=MaxLeftBorderSum=0;

    for(int i=center;i>=Left;i--)

    {

    LeftBorderSum+=A[i];

    if(LeftBorderSum>MaxLeftBorderSum)

    {

    MaxLeftBorderSum=LeftBorderSum;

    }

    }

      

    RightBorderSum=MaxRightBorderSum=0;

    for(int i=center+1;i<=Right;i++)

    {

    RightBorderSum+=A[i];

    if (RightBorderSum>MaxRightBorderSum)

    {

    MaxRightBorderSum=RightBorderSum;

    }

    }

      

    return Max3(MaxLeftSum,MaxRightSum,MaxLeftBorderSum+MaxRightBorderSum);

      

    }

     

    int MaxSubsequenceSum3(const int A[],int N)

    {

    int MaxSum = MaxSubSum(A, 0, N-1);

      

    if(MaxSum==0)

    {

    int i;

    for(i=0;i<N;i++)

    {

    if(A[i]!=0)

    break;

    }

    if(i!=N)

    {

    int Max=A[0];

    for(int j=0;j<N;j++)

    {

    if(A[j]>Max)

    {

    Max=A[j];

    }

    }

    MaxSum=Max;

      

    }

    }

     

    return MaxSum;

     

    }

    这个算法使用了分治的思想,还有递归的思想,即把一个问题不断的分解成类似的规模更小的子问题来解决,所以这里我们要求一个序列的最大子序列,其实就是求左半部分,有伴部分和中间部分的最大子序列,而求左半部分,后半部分的最大子序列显然是将问题的规模变小了,所以可以递归使用,直到剩下一个数的情况.而中间部分呢,则取左右两边,左边从右往左,右边从左往右的最大子序列。然后加起来作为中间部分的值,最后比较中间部分,左半部分,后半部分三部分的值就可以得到结果啦。

     

     

    算法四:

    int MaxSubsequenceSum4(const int A[],int N)

    {

    int thisSum,MaxSum;

    thisSum = MaxSum=0;

      

    for(int i=0;i<N;i++)

    {

    thisSum+=A[i];

    if(thisSum>MaxSum)

    {

    MaxSum=thisSum;

    }

    else if(thisSum<0)

    {

    thisSum=0;

    }

    }

      

      

    if(MaxSum==0)

    {

    int i;

    for(i=0;i<N;i++)

    {

    if(A[i]!=0)

    break;

    }

    if(i!=N)

    {

    int Max=A[0];

    for(int j=0;j<N;j++)

    {

    if(A[j]>Max)

    {

    Max=A[j];

    }

    }

    MaxSum=Max;

      

    }

    }

      

    return MaxSum;

     

    }

     

     

    最后一个算法就比较牛逼啦,这个算法竟然只是N阶的,大家可以想想这个算法的速度有多快,而且如果不考虑全是负数的情况的话,还可以做到随时读入,随时释放内存的强大功能,在此深深膜拜一下。

     








  • 相关阅读:
    Windows操作系统堆和栈的区别
    API1——CppSparseFile
    typedef struct 用法详解和用法小结
    开发人员应该用好的一些网站
    Windows编程中的堆管理
    在VC中编译、运行程序的小知识点
    Script:列出数据库中5%以上链式行的表
    解决Linux上11g的ORA00845错误
    Oracle内部错误:ORA00600[kfioTranslateIO03]一例
    Oracle内部错误:ORA00600[2608]一例
  • 原文地址:https://www.cnblogs.com/BlueMountain-HaggenDazs/p/3898352.html
Copyright © 2011-2022 走看看