为什么需要大O表示法?在对一个程序的好坏做评估时,改程序的时间和空间消耗是很重要的一个评估标准。当数据量增大时,程序运行的时间也会相应的增加,那么增长的幅度是呈指数还是以线性增长呢?这时就需要使用大O表示法来进行估算。
其中,还有一种叫时候统计法的检测方法,即实时监测代码,程序的运行时间和空间,这种方法较大程度受机器的环境和数据量影响,如内存,CPU的好坏,都会直接影响到运行时间的长短,故从便捷程度上来说,大O表示法还是较为舒服。
如下伪代码,估算他的运行时间。
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;
}
}
}
假设代码中每行代码的执行时间为t,则程序中第2~4行共执行了3t,程序5~6行执行了2nt,程序7~8行共执行了2n^2,所以这段代码执行花费了(2n^2 + 2n + 3)t
增长趋势如下图
其中,常数,低阶,系数并不影响这一趋势,故直接舍弃即可,于是只剩下了n^2,所以他的时间复杂度为O(n^2)。
一、对于分析时间复杂度有以下方法
1.关注运行次数最多的
int cal(int n) {
int sum = 0;
int j = 1;
for(; j <= n; j++) {
sum = sum + j;
}
}
在以上伪代码中,第2~3行代码只运行了一次,所以无需关注,而第5行代码运行的次数与n的量级挂钩,所以时间复杂度为O(n).
2.加法法则:总复杂度等于量级最大的那段代码的复杂度
int cal(int n) {
int sum1 = 0;
int j = 1;
for(; j <= n; j++) {
sum1 = sum1 + j;
}
int sum2 = 0
int i = 1;
for(; i <= 1000; i++) {
sum2 = sum2 + i;
}
}
在以上代码代码中,第一段的复杂度为O(n),而第二段为常数,故可忽略不计。可遵循以下公式
T1(n) = O(f(n)),
T2(n) = O(g(n)),
Tn = T1(n) + T2(n) = max(O(f(n)), O(g(n))) = O(max(O(f(n)), O(g(n))));
3.乘法法则:嵌套代码的复杂度等于嵌套内外代码复杂度的乘积
int cal(int n) {
int res= 0;
int j = 1;
for(; j <= n; j++) {
res = res + k(j);
}
}
int k(int n) {
int sum = 0;
int j = 1;
for(; j <= n; j++) {
sum = sum + j;
}
result sum;
}
我们先来看k()的复杂度,很明显,为O(n)。再来看cal的复杂度,很明显,这里出现了嵌套代码,在第五行中调用了k()。在不调用k的情况下,cal()的复杂度为O(n),调用后则使用乘积的形式,则复杂度为O(n * n) = O(n^2)。可遵循以下公式。
Tn = T1(n) * T2(n) = O(n * n) = O(n ^ 2)
二、常见的复杂度量级
多项式量级如下
- 常数阶 O(1)
- 对数阶 O(log n)
- 线性阶 O(n)
- 线性对数阶 O(nlog n)
- 次方阶 平方阶 O(n ^ 2) 立方阶 (n ^ 3) k次方阶(n ^ k)
非多项式量级如下
- 指数阶 O(2 ^ n)
- 阶乘阶 O(n!)
出现两个量级数时如下
- O(m + n)
- O(n * m)
今天先写这么多,有问题欢迎评论。