时间复杂度


时间复杂度

为什么需要 时间复杂度分析

如果 将程序跑一遍,通过统计/监控 得到算法执行的时间和占用的内存(事后统计法)

这样做得到得数据

1.受测试环境影响 2.受数据规模的影响很大

大O复杂度表示法

假设每行代码执行时间一致,每行执行一次为 1个unit_time

int cal(int n) {
  int sum = 0;
  int i = 1;
  int j = 1;
  for (; i <= n; ++i) {
    j = 1;
    for (; j <= n; ++j) {
      sum = sum +  i * j;
    }
  }
}

第 2/3/4 每行 1个unit_time, 5/6 行 n个, 7/8 行 n²个,
执行时间 T(n) = (2n² + 2n + 3) * unit_time

大O 时间复杂度,也称为 渐进式时间复杂度,表示 代码执行时间 随数据规模增长 的变化趋势

当n趋近无穷大,公式中的 低阶 常量 系数 将不影响左右增长趋势,而可以被忽略.

T(n)=O(f(n)),最终,上述代码的 大O时间复杂度 被记为 T(n) = O(n²)

T(n) 总执行时间, F(n) 每行代码总执行次数

时间复杂度分析规则

一段代码

1.只关注循环执行次数最多的一段代码

2.总的时间复杂度就等于量级最大的那段代码的时间复杂度

时间复杂度分析规则类别

最好/最坏时间复杂度:在最理想/最糟糕 的情况下的时间复杂度
(best/worst case time complexity)
平均情况时间复杂度:在平均 的情况下的时间复杂度
(average case time complexity)
加权平均时间复杂度/期望时间复杂度:计算 平均情况时间复杂度 时,加入了概率权重

// 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;
}
// 最好/最坏: O(1),O(n)
// 平均:     元素在0~k~n-1中,需要执行k次,元素在n或不在数组中,需要执行n次,
//           总计n+1种情况,共执行1+2+3...+n+n= n(n+3)/2 次,
//           平均 n(n+3)/2(n+1) 次
// 加权平均: 增加考虑每种情况出现概率权重,
//          假设 1/2 不在数组中,则出现在数组中每个位置概率为w = 1/2n,
//          执行次数为 (1+2+3...+n)*w + n*1/2 = (3n+1)/4

均摊时间复杂度:摊还分析/平摊分析,针对存在规律的 平均情况时间复杂度
的一种分析思想
(amortized case time complexity)

例如 每一次O(n)的操作,会紧跟着n-1次O(1)的操作,将O(n)均摊在n-1次的O(1)上,最终 时间复杂度为O(1)

常见复杂度量级

常数阶O(1)   字典查找、数组索引

对数阶O(logN)   二分查找

线性阶O(n) 循环

线性对数阶O(nlogn) 循环+分而治之

平方阶O(n²)   双重循环

立方阶O(n³) 多重循环

K次方阶O(n^k)

指数阶(2^n)

// logN 对数阶示例
i = 1;
while (i <= n)  {
    i = i * 2;
}

空间复杂度,O(1),O(n),O(n²),表示 算法的储存空间 与数据规模之间 的增长关系


文章作者: 罗紫宇
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 罗紫宇 !
  目录