解析时间复杂度和空间复杂度
说明
时间复杂度和空间复杂度从字面上理解:
-
时间复杂度:指的是执行这段代码所需要的时间,需要的时间越短,算法越好
-
空间复杂度:指的是执行当前算法所需要消耗的存储空间大小。
时间复杂度
时间复杂度的表示方法
一般用大O符号表示法表示,O(f(n)),n是影响复杂度变化的因子,f(n)是复杂度的算法。这个表示方法不是具体的运算时间,而是代码执行时间的增长变化趋势。随着n的增长,算法的执行运算时间增长速度记为f(n)
常见的时间复杂度量级
-
常数阶O(1)
let a=3;
常数阶不会随着变量的增长而增长,永远也只有一次。也就是说我们的代码只需要执行一次就可以得到结果的程序。他的时间复杂度就是常数阶O(1)
-
线性阶O(n)
也就是O(f(n))=O(n),f(n)=n;
for(var i=0;i<n;i++){ }
随着n的增长,算法执行速度f(n)为n,假设n为9,算法执行速度就为9,n为20,算法执行速度为20,
-
对数阶O(logn)
这里的log它的底数为2,假设n为8,f(n)=3=log8,所以对数阶O(logn)当n增长为8倍,算法运算时间只增长3倍, -
线性对数阶O(nlogn)
-
平方阶O(n^2)
-
立方阶O(n^3)
总结
整个时间复杂度的计算就是看变量的增大几倍,运算时间增大的几倍。
空间复杂度
空间复杂度以存储空间的维度来计算,同样的道理,随着n的增大几倍,f(n)占据的空间增大几倍。但实际我们把空间复杂度和时间复杂度放在一起谈。平时分析一个算法优劣的主要依据的分析时间复杂度。
时间复杂度分析
时间复杂度分析的基本策略是:从内向外分析,从最深层开始分析。如果遇到函数调用,要深入函数进行分析。
void aFunc(int n) {
for (int i = 0; i < n; i++) { o(n)
for (int j = i; j < n; j++) {o(n)
printf("Hello World\n"); O(1)
}
}
}
o(n* 2 * 1)=O(n^2),假设n 为2,整个程序执行了3,假设n为8时,外层8次,内层循环从8递减,也就是f(n)=8+7+6+5+4+3+2+1=36;
n增大了4倍,f(n)=增大了12倍,12(f(n))=4(n)*3,所以这个程序的时间复杂度为O(n * 3),递推的话,最后可以得到O(n^2)
void aFunc(int n) {
for (int i = 2; i < n; i++) {
i *= 2;
printf("%i\n", i);
}
}
假设循环次数为 t,则循环条件满足 2^t < n。所以他的时间复杂度是O(logn),
总结
我们分析时间复杂度的目的不是为了精确的计算我们的程序运行次数和时间,而是能够大约的理解我们当前的程序大约会花费多少时间,做哪些改动可以提高程序的运算速度。精确的计算出一个程序的运算时间,以我的数学水平来说,我认为是难搞的。
目前我大约可以认定的时间复杂度:
- 一个循环可以认为O(n)
- 两个循环可以认为O(n^2)
- 一个循环,循环的步长不为1,可以理解为O(logn)