1.3.1 时间复杂度
算法效率的度量
事后统计:不可取
事前预估:预估算法开销与问题规模之间的关系。
时间复杂度
算法时间开销T(n)与问题规模 n之间的关系。
对于顺序和分支语句,n 和 T(n) 为常数。
对于循环,n 与循环次数与循环嵌套层数有关,T(n) 是不确定的。通常以最坏时间复杂度来代表算法的时间复杂度。即当 n -> ∞ 时,用T(n)的同阶无穷大表示,记为O(n)。
三种时间复杂度
-
最坏时间复杂度:最坏情况下,算法执行需要的时间。
-
平均时间复杂度:算法执行的平均时间。
-
最好时间复杂度:算法执行的最小时间。
时间复杂度的计算与比较
例1 单层循环
void delay(int n){
int i=1;
while(i<=n){
i++;
}
}
//指数递增
void delay2(int n){
int i=1;
while(i<=n){
i *= 2;
}
}
int main(){
delay(3000);
}
1)计算
-
delay
- 时间开销与问题规模 n 的关系:T1(n) = 2n+2。
- 当 n -> ∞ 时,(2n+2) /n = 2,,T(n) 与 n 同阶,所以该算法的时间复杂度为: O(n)
-
delay2
- 循环中 i 以指数方式递增:2, 4, 8, …, 2x, 直到 2x >= n, 则 x = log2n ,也是循环执行的次数,所以 T2(n) = 2log2n+2。
- 当 n -> ∞ 时,(2log2n+2) /log2n = 2,,T(n) 与 log2n 同阶,所以该算法的时间复杂度为: O(log2n)
2)比较
当 n -> ∞ 时,log2n/n =(洛必达)= 1/nln2 = 0, 所以 n -> ∞ 的速度远大于 log2n,称 n 为 log2n 的高阶无穷大,称 O(n) 大于 O(log2n) 。
例2 嵌套循环
void delay1(int n){
int i=1;
while(i<=n){
i++;
j = 0;
while(j<=n){
j++;
}
}
}
void delay2(int n){
int i=1;
while(i<=n){
i++;
j = 0;
while(j<=i){
j++;
}
}
}
int main(){
delay1(3000);
}
算法 delay1 的 T1(n) = n(3+2n) = 2n2 + 3n
算法 delay2 的 T2(n) = 3n + 2(1+2+3+…+n) = 3n + 2* (1+n)n/2 = n2 +4n
当 n -> ∞ 时,T1(n) /n2 =2,T2(n) /n2 =1,均与 n2 同阶,所以两个算法的时间复杂度均为: O(n2)
常见时间复杂度
由小到大排列:
O(1) < O(log2n)< O(n) < O(nlog2n)< O(n2) < O(n3) < O(2n) < O(n!) < O(nn)
注意:O(1) 表示 T(n)=C (常数)
四则运算
1)加、减法
T(n) = T1(n) + T2(n) = O(f(n)) + O(g(n)) = O(max(f(n), g(n)))
减法同理。
口诀:相加取大阶。
2)乘、除法
T(n) = T1(n)T2(n) = O(f(n)) O(g(n)) = O(f(n)g(n))
除法同理。
例:
O(n2)+O(n!) = O(n!)
O(n2)O(log2n) = O(nlog2n)