算法效率的度量
算法时间复杂度->T = T(n)
事前预估算法时间开销T(n)与问题规模n的关系(T表示“time”)
//算法1——逐步递增型爱你
void loveYou(int n){ //n为问题规模
1 int i=1; //爱你的程度
2 while(i<=n){
3 i++; //每次加一
4 printf("I Love You %d\n",i);
}
5 printf("I Love You More Than %d\n",n);
}
int main(){
loveYou(3000);
}
语句频度:
1 ——1次
2 ——3001次
3,4 ——3000次
5 ——1次
T(3000) = 1 + 3001 + 2*3000 + 1
时间开销与问题规模n的关系:
T(n) = 3n+3
问题一:是否可以忽略表达式某些部分?
——只考虑阶数,用大O记法表示
时间开销与问题规模n的关系:
- T~1(n) = 3n +3
- T~2(n) = n^2 + 3n+1000
- T~3(n) = n^3 + n^2 + 99999999
结论:可以只考虑阶数高的部分,甚至可以将阶数高的系数忽略
大O表示“同阶”,同等数量级。即:当n->无穷时,二者之比为常数
- T~1(n) = O(n)
- T~2(n) = O(n^2)
- T~3(n) = O(n^3)
T ( n ) = O ( f ( n ) ) < = > l i m ( n − > 无 穷 ) T ( n ) / f ( n ) = k T(n) = O(f(n))<=>lim(n->无穷) T(n)/f(n) = k T(n)=O(f(n))<=>lim(n−>无穷)T(n)/f(n)=k
-
加法规则:多项相加,只保留最高阶的项,且系数变成1
T ( n ) = T 1 ( n ) + T 2 ( n ) = O ( f ( n ) ) + O ( g ( n ) ) = O ( m a x ( f ( n ) , g ( n ) ) ) T(n) = T1(n) + T2(n)=O(f(n))+O(g(n))=O(max(f(n),g(n))) T(n)=T1(n)+T2(n)=O(f(n))+O(g(n))=O(max(f(n),g(n))) -
乘法规则:多项相乘,都保留
T ( n ) = T 1 ( n ) ∗ T 2 ( n ) = O ( f ( n ) ) ∗ O ( g ( n ) ) = O ( f ( n ) ∗ g ( n ) ) T(n)=T1(n)*T2(n)=O(f(n))*O(g(n))=O(f(n)*g(n)) T(n)=T1(n)∗T2(n)=O(f(n))∗O(g(n))=O(f(n)∗g(n))
Eg:T3(n)=n^3 + n^2log~2 n =O(n^3) + O(n^2log~2 n)
=O(n^3)
结论:
O(1) < O(log~2 n) < O(n) < O(nlog~2 n) < O(n^2) < O(n^3) < O(n!) < O(n^n)
口诀:常对幂指阶
问题二:如果有好几千行代码,按这种方式需要一行一行数?
——只需考虑最深层循环的循环次数与n的关系
//算法1——逐步递增型爱你
void loveYou(int n){ //n为问题规模
//插入1000行顺序执行的代码
1 int i=1; //爱你的程度
2 while(i<=n){
3 i++; //每次加一
4 printf("I Love You %d\n",i);
}
5 printf("I Love You More Than %d\n",n);
}
int main(){
loveYou(3000);
}
T(n) = 3n + 1003 = O(n)
结论1:顺序执行的代码只会影响常数项,可以忽略
结论2:只需要挑循环中的一个基本操作分析它的执行次数n的关系即可
//算法2——嵌套循环型爱你
void loveYou(int n){
int i=1;
while(i<=n){ //外层循环执行n次
i++;
printf("I Love You %d\n",i);
for(int j=1;j<=n;j++){//嵌套两层循环
printf("I am Iron Man\n");//内层循环共执行n^2次
}
}
printf("I Love You More Than %d\n",n);
}
int main(){
loveYou(3000);
}
结论3:如果有多层嵌套循环,只需关注最深层循环循环了几次
T(n) = O(n) + O(n^2) = O(n^2)
小练习
算法的时间复杂度
最快时间复杂度:最快情况下算法的时间复杂度
平均时间复杂度:所有输入实例等概率出现的情况下,算法的期望运行时间
最好时间复杂度:最好情况下算法的时间复杂度
总结
小故事:算法的性能问题只有在n很大时才会暴露出来
空间复杂度 S->Space
函数递归调用带来的内存开销
5:n=5,a,b,c
4:n=4,a,b,c
每一层假设为4*4B=16B 几位 kB
如果规模为n 则空间复杂度为nkB