算法的时间复杂度

2 阅读3分钟

算法时间复杂度详解

1. 什么是时间复杂度

时间复杂度(Time Complexity)用于描述算法执行次数随数据规模 n 增长的变化趋势,而不是程序实际运行时间。

例如:

for (int i = 0; i < n; i++) {
    cout << i;
}

循环执行 n 次,因此时间复杂度为:

O(n)

时间复杂度关注的是增长趋势,而不是具体耗时。


2. 大 O 表示法

忽略常数

  • O(3n)O(n)
  • O(100n)O(n)

忽略低阶项

  • O(n²+n)O(n²)
  • O(n³+n²+n)O(n³)

3. 常见复杂度

O(1) 常数 ★★★★★
O(log n) 对数 ★★★★★
O(√n) 平方根 ★★★★☆
O(n) 线性 ★★★★
O(n log n) 线性对数 ★★★
O(n²) 平方 ★★
O(n³) 立方
O(2ⁿ) 指数 极慢
O(n!) 阶乘 几乎不可用

4. 如何计算时间复杂度

4.1 基本语句

a++;

执行一次,因此:

O(1)

4.2 顺序结构

复杂度相加,保留最高阶。

例如:

for (...) {}
for (...) {}

总复杂度:

O(n)+O(n)=O(n)

若为:

O(n²)+O(n)=O(n²)

4.3 单层循环

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

复杂度:

O(n)

若循环到 n/2

for(int i=0;i<n/2;i++)

仍为:

O(n)

固定循环 100 次:

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

复杂度:

O(1)

4.4 嵌套循环

两层:

for(...)
    for(...)

复杂度:

O(n²)

三层:

O(n³)

4.5 循环次数变化

for(i=0;i<n;i++)
    for(j=0;j<i;j++)

执行次数:

0+1+2+...+(n-1)

根据公式:

n(n-1)/2

因此:

O(n²)

4.6 每次翻倍或减半

for(int i=1;i<n;i*=2)

或:

while(n>1)
    n/=2;

复杂度:

O(log n)

4.7 n × log n

for(...)
    while(...)

若:

  • 外层:O(n)
  • 内层:O(log n)

总复杂度:

O(n log n)

4.8 递归

线性递归
T(n)=T(n-1)+O(1)

复杂度:

O(n)
对数递归
T(n)=T(n/2)+O(1)

复杂度:

O(log n)
主定理常见结论
T(n)=2T(n/2)+O(1) O(n)
T(n)=2T(n/2)+O(n) O(n log n)
T(n)=2T(n-1)+O(1) O(2ⁿ)

5. 经典例题

例1

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

答案:

O(n)

例2

for(i=0;i<n;i++)
    for(j=0;j<n;j++)

答案:

O(n²)

例3

for(i=1;i<n;i*=2)

答案:

O(log n)

例4

for(i=0;i<n;i++)
    for(j=1;j<n;j*=2)

答案:

O(n log n)

例5

for(i=0;i<n;i++)
    for(j=i;j<n;j++)

执行次数:

n+(n-1)+...+1

复杂度:

O(n²)

6. 分析口诀

  1. 基本语句:O(1)
  2. 顺序结构:相加取最高阶
  3. 嵌套循环:复杂度相乘
  4. 每次加减常数:通常 O(n)
  5. 每次乘除常数:通常 O(log n)
  6. 求和型循环:先求执行次数再化简
  7. 递归:写递推式,再分析

7. 速查表

常数操作 O(1)
每次翻倍/减半 O(log n)
固定次数循环 O(1)
单层循环 O(n)
循环到 n/2 O(n)
外层 n、内层 log n O(n log n)
双重循环 O(n²)
0+1+…+n O(n²)
三重循环 O(n³)
T(n)=T(n/2)+O(1) O(log n)
T(n)=T(n-1)+O(1) O(n)
T(n)=2T(n/2)+O(n) O(n log n)