引入
前面我们讲了普通赋值、输出、打印的时间复杂度、也讲了循环、嵌套循环的时间复杂度,现在我们来看看在函数引用下,时间复杂度有什么不同。
例子
看看下面程序的时间复杂度
1 | int i; //执行1次 |
上面的循环语句,每执行一次,就会调用一次函数,函数是 1,循环 n 次 1 ,所以上面这个例子的时间复杂度是 O(n) 。
我们再来个复杂点的
1 | int i; //执行1次 |
这样一来,for 循环调用函数 n 次,每次函数内都执行 (n+1)/2 次循环。和之前的例子一样$n(n+1)/2=n^2/2+n/2$,根据时间复杂度三个法则,保留最高项,去掉非1最高项的乘数。那结果就是$O(n^2)$。
我们再提升一下难度:
1 | int i; //执行1次 |
所以就是
$1+n^2+1+n+n^2+n^2=3n^2+n+2$
根据三法则
- 去掉加的常数:$3n^2+n$
- 只保留最高阶:$3n^2$
- 去掉非1最高阶的乘数:$n^2$
- 答案是:$n^2$
常见时间复杂度
上面的三个例子,我们对时间复杂度应该有了基本认识,我们来看看常见的时间复杂度。
例子 | 时间复杂度 | 术语 |
---|---|---|
$123456$ | O(1) | 常数阶 |
$3n+4$ | O(n) | 线性阶 |
$3n^2+4n+5$ | O($n^2$) | 平方阶 |
$3log(2)n+4$ | O($logn$) | 对数阶 |
$2n+3nlog(2)n+14$ | O($nlogn$) | nlog阶 |
$n^3+2n^2+4n+5$ | O($n^3$) | 立方阶 |
$2^n$ | O($2^n$) | 指数阶 |
我们来看看图
从这个图中,我们可以很清楚的看到:
- 常数阶和线性阶:常数阶因为是一条直线,一开始比对线性阶要差。但是线性阶的斜率不为0,是缓慢增加的,所以随着输入规模增大,线性阶就不如常数阶那么好用了。
- 常数阶和对数阶:跟线性阶一样,对数阶的斜率要小,所以爬升速度慢,但也在起步落后的情况下,超过了常数阶。
- Nlog 阶和平方阶:之前的图觉得 nlog 阶一枝独秀,增长非常快,但发现平方阶爬升速度更快。
- 立方阶:立方阶爬升速度已经石井人的了。
- 立方阶和指数阶:我们单独把这两个爬升最快拿出来,发现原来速度很快的立方阶,也远远赶不上指数阶。
所以,根据上面的表格和折线,我们总结出如下规律
O( 1 ) < O( log n ) < O(n)< O( nlogn )
O( nlogn ) < O( $n^2$ ) < O( $n^3$ ) < O( $2^n$ )
O( $2^n$ ) < O( $n!$ ) < O( $n^n$ )
再强调一次,我们不是要追求最大,这里的数值表示的是随着输入规模增大后,计算所需要的步骤,所以步骤越少越好
。
尾巴
这是我的个人学习笔记,主要是应付考研复习使用,充斥着一些吐槽和个人观点,并不严谨,欢迎大家参考、指正。