• 算法01


    认识时间复杂度:

    • 常数时间的操作:一个操作如果和数据量没有关系,每次都是 固定时间内完成的操作,叫做常数操作。
    • 时间复杂度为一个算法流程中,常数操作数量的指标。常用O (读作big O)来表示。具体来说,在常数操作数量的表达式中, 只要高阶项,不要低阶项,也不要高阶项的系数,剩下的部分 如果记为f(N),那么时间复杂度为O(f(N))。
    • 评价一个算法流程的好坏,先看时间复杂度的指标,然后再分 析不同数据样本下的实际运行时间,也就是常数项时间。

    对数器的概念和使用:

    • 有一个你想要测的方法a
    • 实现一个绝对正确但是复杂度不好的方法b
    • 实现一个随机样本产生器
    • 实现比对的方法
    • 把方法a和方法b比对很多次来验证方法a是否正确
    • 如果有一个样本使得比对出错,打印样本分析是哪个方法出错
    • 当样本数量很多时比对测试依然正确,可以确定方法a已经 正确

    冒泡排序细节的讲解与复杂度分析,时间复杂度O(N^2),额外空间复杂度O(1)

    void  Bubble_sort(int *t,int len)
    {
        for(int i=len-1;i>0;i--)
        {
            for(int j=0;j<i;j++)
            {
                if(t[j]<t[j+1])
                    swap(t[j],t[j+1]);
            }
        }
    }

    选择排序的细节讲解与复杂度分析,时间复杂度O(N^2),额外空间复杂度O(1)

    void Selection_sorting(int *t,int len)
    {
        for(int i=0;i<len-1;i++)
        {
            int item=i;
            for(int j=i+1;j<len;j++)
            {
                item=t[item]<t[j]?item:j;
            }
            swap(t[i],t[item]);
        }
    }

    插入排序的细节讲解与复杂度分析时间复杂度O(N^2),额外空间复杂度O(1)

    void Insertion_sort(int *t,int len)
    {
        for(int i=1;i<len;i++)
        {
            for(int j=i;j>0;j--)
            {
                if(t[j]<t[j-1])
                {
                    swap(t[j],t[j-1]);
                }
            }
        }
    }

    冒泡排序和选择排序,这两种排序不管你的数据状况是什么样的,时间复杂度都是O(n*n),但是插入排序的时间复杂度和数据本身的状况有关,但是我们在定义一个算法的时间复杂度往往是用最坏的情况去考虑,所以插入排序的时间复杂度也是O(n*n),但是我们要知道他和选择冒泡排序是有区别的。

    下面我用一个小的例子来介绍一下递归算法的时间复杂度分析:

    例子:求一个数组的最大值 1 int get_max(int *t,int left,int right)

     1 int get_max(int *t,int left,int right)
     2 {
     3     if(left==right)
     4     {
     5         return t[left];
     6     }
     7     int mid = left+((right-left)>>1);//这个地方下面有讲解
     8     //这个地方最简单可以写为 mid = (left + right)/2;但是这样可能有风险,可能会溢出
     9     //改进后 mid = left+(right-left)/2;这样就能防止溢出
    10     //然后(right -left)/2  改为((right-left)>>1) 位运算的操作更快
    11     int max1 = get_max(t,left,mid);
    12     int max2 = get_max(t,mid+1,right);
    13     if(max1>max2)  return max1;
    14     return max2;
    15 }

    这里这个递归算法的时间复杂度可以写成 T(N) = aT(N/b) + O(n^d),的形式,N代表数据的规模,a代表执行次数(在这个算法里面就是第11行和第12行代码),b的意思就是递归行为将原来的数据分成了多少份(在这里是两份),n^d代表的就是除了递归行为其他其他行代码的时间复杂度(在这里由于其他项代码的时间复杂度是一个常数项,所以d=0)

    只要满足T(N) = a*T(N/b) + O(N^d)的形式,就可以使用master公式求解这个式子的时间复杂度。

    1. log(b,a) > d -> 复杂度为O(N^log(b,a))
    2. log(b,a) = d -> 复杂度为O(N^d * logN) 
    3. log(b,a) < d -> 复杂度为O(N^d)

     但是一定得是T(N) = a*T(N/b) + O(N^d),才可以使用master公式来求解递归算法的时间复杂度

    归并排序的细节讲解与复杂度分析时间复杂度O(N*logN),额外空间复杂度O(N)

     1 void Merging_sort1(int *t,int len)
     2 {
     3     if(NULL==t||len<2)
     4     {
     5         return;
     6     }
     7     Merging_sort2(t,0,len-1);
     8 }
     9 
    10 void Merging_sort2(int *t,int left,int right)
    11 {
    12     if(left==right)
    13     {
    14         return;
    15     }
    16     int mid = left + ((right - left)>>1);
    17     Merging_sort2(t,0,mid);
    18     Merging_sort2(t,mid+1,right);
    19     Merge(t,left,right);
    20 }
    21 
    22 void Merge(int *data,int left,int right)
    23 {
    24     int mid = left + ((right - left)>>1);
    25     int *help = new int[right-left+1];
    26     int p1=left;
    27     int p2=mid+1;
    28     int index=0;
    29     while(p1<=mid&&p2<=right)
    30     {
    31         help[index++]=data[p1]>data[p2]?data[p1++]:data[p2++];
    32     }
    33     while(p1<=mid)
    34     {
    35         help[index++]=data[p1++];
    36     }
    37     while(p2<=right)
    38     {
    39         help[index++]=data[p2++];
    40     }
    41 
    42     for(int i=0; i<index; i++)
    43     {
    44         data[i+left]=help[i];
    45     }
    46     delete [] help;
    47 }

    看完了归并排序的整个过程,我们就可以使用master公式来对归并排序的时间复杂度进行计算;

    归并排序之所以能够做到时间复杂度为 N*(logN) 是因为他在外排的过程中没有多余的比较,只是组与组之间的比较,组内已经有序,所以不像冒泡选择排序那样有很多没有用的比较;

    好了学习完归并排序之后我们就可以来做几道题目

    题目1:小和问题

    在一个数组中,每一个数左边比当前数小的数累加起来,叫做这个数组的小和。

    求一个数组 的小和。

    • 比如[1,3,4,2,5]
    • 1左边比1小的数,没有;
    • 3左边比3小的数,1;
    • 4左边比4小的数,1、3;
    • 2左边比2小的数,1;
    • 5左边比5小的数,1、3、4、2;
    • 所以小和为1+1+3+1+1+3+4+2=1。

    这道题目就可以使用归并排序:

    int Merging_sort1(int *t,int len)
    {
        if(NULL==t||len<2)
        {
            return 0;
        }
        return Merging_sort2(t,0,len-1);
    }
    
    
    int  Merging_sort2(int *t,int left,int right)
    {
        if(left==right)
        {
            return 0;
        }
        int mid = left + ((right - left)>>1);
        return Merging_sort2(t, left, mid) + Merging_sort2(t, mid + 1, right) + Merge(t, left, right);
    }
    
    int  Merge(int *data,int left,int right)
    {
        int mid = left + ((right - left)>>1);
        int *help = new int[right-left+1];
        int p1=left;
        int p2=mid+1;
        int index=0;
        int res=0;
        while(p1<=mid&&p2<=right)
        {
            res += data[p1] < data[p2] ? (right - p2 + 1) * data[p1] : 0;
            help[index++]=data[p1]<data[p2]?data[p1++]:data[p2++];
        }
        while(p1<=mid)
        {
            help[index++]=data[p1++];
        }
        while(p2<=right)
        {
            help[index++]=data[p2++];
        }
    
        for(int i=0; i<index; i++)
        {
            data[i+left]=help[i];
        }
        delete [] help;
        return res;
    }

    将归并排序的代码稍微改动一下就能很好的解决这个问题

  • 相关阅读:
    fgets()函数读取键盘,去掉换行符或丢弃多余的字符
    c语言gets()函数与它的替代者fgets()函数
    基于京东手机销售数据用回归决策树预测价格
    「我去,这也能行!」令人惊叹的8个深度学习应用
    常见数据结构的 Python 实现(建议收藏)
    60 分钟极速入门 PyTorch
    大牛推荐的15本学习数据分析挖掘的好书
    排名前20的网页爬虫工具
    如何11 周打造全能Python工程师!
    初学者的编程自学指南
  • 原文地址:https://www.cnblogs.com/luojianyi/p/9337570.html
Copyright © 2020-2023  润新知