前文介绍了:什么是大O时间复杂度,以及如何计算大O时间复杂度。虽然不同算法的代码会有不同,但通过前文所述“大O时间复杂度计算方法”计算后,常见的复杂度并不多,除了前文说到的O(1)、O(n),相信大家一定也经常见到O(n²)、O(logn)、O(nlogn)等复杂度,本文就列举下这些常见复杂度情况并简单介绍下空间复杂度的概念。
常见时间复杂度
常数阶 O(1)
注:一般的,不论算法代码有多少行,只要其中没有循环、递归,按前文所介绍计算方法,其时间复杂度都是Ο(1)。
示例:
1 public int fun1(int n1,int n2 ){
2 int sum = n1 +n2;
3 return sum;
4 }
对数阶 O(logn)
注:对数阶是其中最常见,同时也是最难分析的。以下边算法fun2举例,其中变量i的值从1开始,每循环一次就乘以2,当其大于n时,循环结束。所以随着循环执行i的值依次为
![99107725d799e80f5e9519b118a65755.png](https://i-blog.csdnimg.cn/blog_migrate/1d1451decf63a13c28fbd6f20f792731.jpeg)
,也就是一个以2为底的等比序列。如果i是每次循环都乘以3,那么等比数列的底就是3。并且,数列中每一项都小于n,所以如果我们求解出x的值,也就知道总共循环了多少次,即求解 中x的值,通过指数与对数相关运算可知:
![e38169a4a645343d5ddcba7697e74b32.png](https://i-blog.csdnimg.cn/blog_migrate/1a37215bf588f93664f77143008a6732.png)
。另外,因为
![2abb3f443e6cc193b5dde5a5deb9f3f5.png](https://i-blog.csdnimg.cn/blog_migrate/8134bb5ef8fa85791dbc4b3737322532.png)
而log32是个常数,所以根据前文忽略常数原则,最终大O复杂度为O(logn):
1 public int fun2(int n){
2 int i=1;
3 while (i <= n) {
4 i = i * 2;
5 }
6 return i;
7 }
线性阶 O(n)
注:因为for循环中的代码会执行n遍,所以当n很大时候,执行时间跟n比较相关,忽略常数项、最高项系数,所以时间复杂度是O(n)
1 public int fun(int n){
2 int s = 0;
3 for (int i = 0; i < n; i++) {
4 s += i;
5 }
6 return s;
7 }
常数对数阶 O(nlogn)
注:上边已经结束了对数阶、常数阶,这里常数对数阶就比较容易理解。
1 public int fun4(int n){
2 int s=1;
3 for (int i = 0; i < n; i++) {
4 while (i <= n) {
5 i = i * 2;
6 }
7 }
8 return s;
9 }
平方阶 O(n^2)
注:上文有提到过循环使用“乘法”,这里是两次循环,所以是。类似的,如果内外层循环次数不一样,比如外层是n,里层是m,此时复杂度是 m n∗m 。
1 public int fun5(int n){
2 int s = 0;
3 for (int i = 0; i < n; i++) {
4 for (int j = 0; j < n; j++) {
5 s = i*j;
6 }
7 }
8 return s;
9 }
空间复杂度
对比时间复杂度,空间复杂度就比较好理解了,它是对一个算法在运行过程中占用内存空间大小的度量。与时间复杂度一样,空间复杂度也是关于数据量n的函数,比较常见的空间复杂度有O(1)、O(n)、O(n^2),更复杂度对数阶、常数对数阶平时是用不到的。
在实际应用过程中,时间复杂度和空间复杂度是很难二者兼得的,也就有了所谓的”用空间换时间“、”用时间换空间“的说法,也就是说如果想最求时间短,那么空间使用就会多些,如果最求空间使用少,那么时间就会相对长些。不过,大多数情况下都会更看重时间复杂度,因为从用户体验上看,时间段的话体验会更好些,这也就催生了一些”用空间换时间“的缓存产品 (memcache、redis)和算法(基数排序)。
常见复杂度对比图
![70534537833ac2c3de371d76a8d407a0.png](https://i-blog.csdnimg.cn/blog_migrate/644813c5aea1f806dff4ae1ed3858f8c.jpeg)
从上图可以看出,随着数据量n不断增大,不同复杂度的时间增速是差别比较大的,一般情况下是:
![931f2e842c68371d19111cfafd3e93d0.png](https://i-blog.csdnimg.cn/blog_migrate/da800126a2ed25541d8ed8b3af67e71b.jpeg)
所以要尽可能的使用增速慢的算法。
![998ade382e5f70d92c71072c925f1fc8.png](https://i-blog.csdnimg.cn/blog_migrate/e2cf1ca70c8a671f9eff96a03ed25b19.jpeg)