zoukankan      html  css  js  c++  java
  • 算法复杂度分析(下):最好、最坏、平均、均摊等时间复杂度概述

    细化时间复杂度分析

    代码千千万,有些代码逻辑会很复杂,所以为了更细化的分析算法的复杂度,再复杂度分析方面引入了4个知识点:

    1.最好情况时间复杂度(best case time complexity)。

    2.最坏情况时间复杂度(worst case time complexity)。

    3.平均情况时间复杂度(average case time complexity)。

    4.均摊时间复杂度(amortized time complexity)。

    复杂度分析 

    示例如下(限定条件:0<n且0<x且n和x为整数):

     1 public int Function(int n, int x)
     2  {
     3      int sum = 0;
     4      for (int i = 1; i <= n; ++i)
     5      {
     6          if (i == x)
     7              break;
     8          sum += i;
     9      }
    10      return sum;
    11  }
    12  /*
    13  * 作者:Jonins
    14  * 出处:http://www.cnblogs.com/jonins/
    15  */

    这段代码逻辑非常简单,再此不描述。需要重点分析的是循环这一段代码,这段代码根据x值的不同,时间复杂度也有区别:

    1.当x>n时,此代码的时间复杂度是O(n)

    2.当1<=x<=n时,时间复杂度是一个我们不确定的值,取决于x的值。

    3.当x=1时,时间复杂度是O(1)

    这段代码在不同情况下,其时间复杂度是不一样的。所以为了描述代码在不同情况下的不同时间复杂度,我们引入了最好最坏平均时间复杂度

    最好情况时间复杂度

    最好情况时间复杂度,表示在最理想的情况下,执行这段代码的时间复杂度。

    上述示例就是当x=1的时候,循环的第一个判断就跳出,这个时候对应的时间复杂度就是最好情况时间复杂度。

    最坏情况时间复杂度

    最坏情况时间复杂度,表示在最糟糕的情况下,执行这段代码的时间复杂度。

    上述示例就是n<x的时候,我们要把整个循环执行一遍,这个时候对应的时间复杂度就是最坏情况时间复杂度。

    平均情况时间复杂度

    最好和最好情况是极端情况,发生的概率并不大。为了更有效的表示平均情况下的时间复杂度,引入另一个概念:平均情况时间复杂度

    分析上面的示例代码,判断x在循环中出现的位置,有n+1种情况:1<=x<=n 和n<x

    我们将所有情况下代码执行的次数累加起来1+2+3....+n)+n,然后再除以所有情况数量(n+1),就可以得到需要遍历次数的平均值。

    平均情况复杂度为:

    $ frac{((1+2+3...+n)+n)}{(n+1)}=frac{n(n+3)}{2(n+1)} $

    推导过程:

    $ ecause 1+2+3...+n=n+(n-1)+(n-2)...+1 $

    $ herefore (1+2+3...+n)=frac{n(1+n)}{2} $

    $  herefore   (1+2+3...+n)+n= frac{n(3+n)}{2} $

    大O表示法,会省略系数、低阶、常量,所以平均情况时间复杂度是O(n)

    但是这个平均复杂度没有考虑各自情况的发生概率,这里的n+1情况,它们的发生概率是不一样的,所以还需要引入各自情况发生的概率再具体分析。

    x要么在1~n中,要么不在1~n中,所以它们的概率都是$frac{1}{2}$

    同时数据在1~n中各个位置的概率都是一样的为$frac{1}{n}$。根据概率乘法法则,x在1~n中任意位置的概率是$frac{1}{2n}$

    因此在前面推导过程的基础上,我们把每种情况发生的概率考虑进去,那么平均情况时间复杂度的计算过程变成:

    考虑概率的平均情况复杂度为:

    $(1frac{1}{2n}+2frac{1}{2n}+3frac{1}{2n}...+nfrac{1}{2n})+nfrac{1}{2}=frac{3n+1}{4}$

    推导过程:

    $ecause (1+2+3...+n)=frac{n(1+n)}{2}$ 

    $ herefore (1frac{1}{2n}+2frac{1}{2n}+3frac{1}{2n}...+nfrac{1}{2n})=frac{1}{2n}(1+2+3...+n)=frac{1}{2n}*frac{n(1+n)}{2} =frac{1+n}{4}$ 

    $ herefore (1frac{1}{2n}+2frac{1}{2n}+3frac{1}{2n}...+nfrac{1}{2n})+nfrac{1}{2}=frac{1+n}{4} +nfrac{1}{2}=frac{3n+1}{4}$ 

     

    这就是概率论中的加权平均值,也叫做期望值,所以平均时间复杂度全称叫:加权平均时间复杂度或者期望时间复杂度

    引入概率之后,平均复杂度变为O($frac{3n+1}{4}$),忽略系数及常量后,最终得到加权平均时间复杂度为O(n)。

    注意:

    多数情况下,我们不需要区分最好、最坏、平均情况时间复杂度。只有同一块代码在不同情况下时间复杂度有量级差距,我们才会区分3种情况,为的是更有效的描述代码的时间复杂度。

     

    均摊情况时间复杂度

    均摊复杂度是一个更加高级的概念,它是一种特殊的情况,应用的场景也更加特殊和有限。

    对应的分析方式称为:摊还分析或平摊分析。

    示例如下(限定条件:0<=x<=n且0<=n且n,x为整数):

     1 int n;
     2 int Function2(int x)
     3 {
     4     int count = 0;
     5     if (n == x)
     6     {
     7         for (int i = 0; i < n; i++)
     8         {
     9             count += i;
    10         }
    11     }
    12     else
    13         count = x;
    14     return count;
    15 }
    16 /* 作者:Jonins
    17 * 出处:http://www.cnblogs.com/jonins/
    18 */

    分析上述案例的时间复杂度:

    最理想情况下x!=n,只执行一次赋值即可推出,所以最好时间复杂度为O(1)。

    最坏的情况下x=n,要执行一次循环累加和的操作,所以最好时间复杂度为O(n)。

    平均的情况下,因为限定条件0<=x<=n,x在0~n中存在的位置可以分为n+1种情况(0到n)。

    0<=x<n时,时间复杂度为O(1)。但是x=n的时候是一个例外,它的复杂度是O(n)。

    而且这n+1种情况发生的概率都是一样的,为$frac{1}{n+1}$。所以根据加权平均的计算方法,

    平均时间复杂度为:

    $ (1 frac{1}{n+1}+1 frac{1}{n+1}+1 frac{1}{n+1}+...+1 frac{1}{n+1})+n frac{1}{n+1} =  frac{2n}{n+1} $

    推导过程:

    $(1 frac{1}{n+1}+1 frac{1}{n+1}+1 frac{1}{n+1}+...+1 frac{1}{n+1})+n frac{1}{n+1}$

    $=n frac{1}{n+1}+n frac{1}{n+1}$

    $= frac{2n}{n+1}$

    当省略系数及常量后,平均时间复杂度为O(1)。

    摊还分析法

    分析上述示例的平均复杂度分析并不需要如此复杂,无需引入概率论的知识。

    因为通过分析可以看出,上述示例代码复杂度大多数为O(1),极端情况下复杂度才较高为O(n)。同时复杂度遵循一定的规律,一般为1个O(n),和n个O(1)。针对这样一种特殊场景使用更简单的分析方法:摊还分析法

    通过摊还分析法得到的时间复杂度为均摊时间复杂度

    大致思路:每一次O(n)都会跟着n次O(1),所以把耗时多的复杂度均摊到耗时低的复杂度。得到的均摊时间复杂度为O(1)。

    应用场景:均摊时间复杂度和摊还分析应用场景较为特殊,对一个数据进行连续操作,大部分情况下时间复杂度都很低,只有个别情况下时间复杂度较高。而这组操作其存在前后连贯的时序关系。

    这个时候我们将这一组操作放在一起分析,将高复杂度均摊到其余低复杂度上,所以一般均摊时间复杂度就等于最好情况时间复杂度。

    注意:均摊时间复杂度是一种特殊的平均复杂度(特殊应用场景下使用),掌握分析方式即可。

    作者:Jonins    出处:http://www.cnblogs.com/jonins/
     
    个人原创,若有错误或补充请联系作者。
     
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    [译]为什么你要学Go?
    类Lisp解释器JavaScript实现
    前端同学Windows中生存指北
    Virtualbox
    数据发布和上线日报&周报系统开发总结
    [Lab1]五分钟了解Makefile
    解决linux下解压来自windows的zip文件产生乱码的问题
    Arch使用过程中出现的问题汇总
    jQuery为什么移除了.toggle()方法
    Linux配置DNS
  • 原文地址:https://www.cnblogs.com/jonins/p/9956752.html
Copyright © 2011-2022 走看看