【Algo】复杂度分析 -- 最好, 最坏, 平均, 均摊 时间复杂度

Backto Algo Index

上一篇说到了 Big-O 分析法, 但是那只适合分析复杂度随着 n n n 增大的趋势, 实际生产中, 我们还需要知道更细节的指标, 比如

  • 最好情况时间复杂度 best case time complexity
  • 最坏情况时间复杂度 worst case time complexity
  • 平均情况时间复杂度 average case time complexity
  • 均摊时间复杂度 amortized time complexity

Best, Worst & Average

先上代码

// n 表示数组 array 的长度
int find(int[] array, int n, int x) {
   int i = 0;
   int pos = -1;
   for(; i < n; ++i) {
     if(array[i] == x) {
       pos = i;
       break;
     }
   }
   return pos;
}

很简单的, 在一个数组中 find 一个数是否存在, 逐一分析,

  • Best case : x = array[0], 一击即中, 复杂度 O ( 1 ) O(1) O(1)
  • Worst case : x = array[n-1], 或者 x not in array, 那么需要找 n n n 次, 复杂度 O ( n ) O(n) O(n)
  • Average case : 平均就必要有意思了, 需要看你怎么分配权重, 或者说概率
    • 均值分布, 一共有 n + 1 n+1 n+1 种可能, 每个的概率 是 1 n + 1 \frac 1 {n+1} n+11, 那么期望就是 1 + 2 + 3 + . . . + n + n n + 1 = n ( n + 3 ) 2 ( n + 1 ) \frac {1 + 2 + 3 + ... + n + n}{n+1} = \frac {n(n+3)}{2(n+1)} n+11+2+3+...+n+n=2(n+1)n(n+3), 用 Big-O 分析, 省略常数项和低阶项, 就是 O ( n ) O(n) O(n)
    • 随机分布, 给定每一种 case 不同的概率, 自然也就导致了不同的期望

均摊复杂度分析

不同与前面三个通用的简单的case, 均摊复杂度分析对应的是一种特殊的case

如果一个复杂度很高的操作, 会导致后面一连串复杂度很低的操作, 那么我们就可以把第一个操作的高复杂度均摊到后面的低复杂度上, 进而分析整体的复杂度. 这一类中最好的例子就是 insert

int[] arry = new int[n];
int count = 0;

void insert(int val) {
  if(count == array.length) {
    int sum = 0;
    for(int i=0; i < array.length; ++i)
      sum += array[i]
   
   array[0] = sum;
   count = 1;
  }
  
  array[count] = val;
  ++count;  
}

这段代码的意思是向一个数组中 insert 数字, 如果有空位则直接插入, 是 O ( 1 ) O(1) O(1), 如果没有空位, 则把所有已有的数字求和置于数组首位, 再从第二个位置开始插入, 求和这波操作的复杂度就是 O ( n ) O(n) O(n), 如果我们用平均算一下, 就是 1 + 1 + 1 + . . . + 1 + n n + 1 = 2 n n + 1 \frac {1 + 1 + 1 + ... + 1 + n}{n+1} = \frac{2n}{n+1} n+11+1+1+...+1+n=n+12n, 用 Big-O 记做 O ( 1 ) O(1) O(1).

观察发现, 每一次数组满员, 触发 1 次复杂度为 n n n 的操作之后, 都会紧跟着 n − 1 n - 1 n1 个复杂度为 1 1 1 的操作, 我们视这一组操作为一个原子操作, 均摊复杂度, 就是 O ( 1 ) O(1) O(1). 可见均摊就是加权平均的一个特例, 这里单拎出来,也是因为这个操作比较特殊, 也比较常见, 比如除了上面的 insert 还有 add, C++ vector 中push数据, 如果push 满了, 就新开辟一个2倍的空间出来, 把原来的值copy过去, 这一波是 O ( n ) O(n) O(n), 之前和之后的一个一个插, 都是 O ( 1 ) O(1) O(1), 平均下来复杂度就是 O ( 1 ) O(1) O(1). 由此也可以联想到, 虽然 vector 是变长的, 但是能给定大小的情况下还是要给定capacity, 这样像 add 这样的操作就完全变成了 O ( 1 ) O(1) O(1).

你可能感兴趣的:(Algo)