前言
很久之前就听过时间复杂度和空间复杂度,只知道它们是用来形容算法的,可对于其真实含义,却一知半解,今天终于抽出时间来了解一下!
一、定义
算法复杂度:分为时间复杂度和空间复杂度。
时间复杂度:指执行算法所需要的计算工作量,通过这个来衡量算法运行时间的多少。时间复杂度常用大O符号表述。
常见的时间复杂度有:
常数阶O(1)
对数阶O(log2n)
线性阶O(n)
线性对数阶O(nlog2n)
平方阶O(n^2),
立方阶O(n^3)
k次方阶O(n^K),
指数阶O(2^n)
随着问题规模n的不断增大,上述时间复杂度不断增大,算法的执行效率越低。
空间复杂度(Space Complexity):类似于时间复杂度,指执行算法所需要的内存空间。空间复杂度(Space Complexity)是对一个算法在运行过程中临时占用存储空间大小的量度。
二、如何计算
首先通过几个典型的 例子来看看
1、常数阶O(1)
public void o1Test(int n) {
int i = 1;
int j = 2;
int k = 3;
}
无论n如何增大,上面三条语句的执行频率都是1,也就是执行时间是与问题规模无关的常数,这时候的时间复杂度就是常数阶O(1),同理空间复杂度也是O(1)
2、对数阶O(log2n)
public void o2Test(int n) {
int i = 1;//语句1
while(i < =n) {//语句2
i *= 2;
}
}
语句1的频率为1
设语句2的频度是f(n),
则:
2^f(n)<=n;
f(n)<=log2n
取最大值f(n)=log2n,
因此时间复杂度为 T(n)=O(log2n )
只有一个变量i占了空间,因此空间复杂度为O(1)
3、线性阶O(n)
public void o3Test(int n) {
int i = 1;// 语句1
for (int j = 0; j < n; j++) {// 语句2
i++;// 语句3
}
}
语句1的频率为1
语句2的频度为n+1
语句3的频率为n
因此时间复杂度为:T(n)=1+n+1+n=2n+2=O(n)
空间复杂度:变量i和j分别占一个空间,T(n)=1+1=2=O(1)
4、平方阶O(n^2)
public void o4Test(int n) {
int i = 1;// 语句1
for (int j = 0; j < n; j++) {// 语句2
for (int k = 0; k < n; k++) {// 语句3
i++;//语句4
}
}
}
语句1的频率为1
语句2的频度为n+1
语句3的频率为(n+1)^2
语句4的频率为(n+1)^2
因此时间复杂度为:T(n)=1+n+1+2(n+1)^2
=2n^2+5n+6
=O(n^2)
空间复杂度:变量i,j和k分别占一个空间,T(n)=1+1+1=3=O(1)
5、指数阶O(2^n)
public int o5Test(int n) {
if (n < 0) {
return -1;
} else if (n > 0 && n < 3) {
return 1;
} else {
return o5Test(n - 1) + o5Test(n - 2);
}
}
以上算法其实就是斐波那契数列的算法,实现过程就是二叉树。
用f(n)表示方法o5Test(int n),
若n = 3,则f(3) = f(2) + f(1),相当于2^(3-2)
若n = 4,则f(4) = f(3) + f(2) = f(3) + f(2) + f(2) + f(1),相当于2^(4-2)
若n = 5,则f(5) =f(4) + f(3) = f(4) + f(3) + f(3) + f(2) + f(2) + f(1) + f(2) + f(1),相当于2^(5-2)
若n = n,则2^(n-2)
因此时间复杂度为:
T(n)=2^(n-2)
=O(2^n)
空间复杂度为O(1)
二、总结
以上是求时间复杂度和空间复杂度的具体步骤,现在将一些计算规律总结如下。
1、求解算法时间复杂度的具体步骤
(1) 找出算法中的基本语句;
算法中执行次数最多的那条语句就是基本语句,通常是最内层循环的循环体。
(2) 计算基本语句的执行次数的数量级;
只需计算基本语句执行次数的数量级,这就意味着只要保证基本语句执行次数的函数中的最高次幂正确即可,可以忽略 所有低次幂和最高次幂的系数。这样能够简化算法分析,并且使注意力集中在最重要的一点上:增长率。
(3) 用大Ο记号表示算法的时间性能。
将基本语句执行次数的数量级放入大Ο记号中
2、在计算算法时间复杂度时有以下几个简单的程序分析法则
(1)对于一些简单的输入输出语句或赋值语句,近似认为需要O(1)时间
(2)对于顺序结构,需要依次执行一系列语句所用的时间可采用大O下"求和法则"
求和法则:是指若算法的2个部分时间复杂度分别为 T1(n)=O(f(n))和 T2(n)=O(g(n)),则 T1(n)+T2(n)=O(max(f(n), g(n)))
(3)对于选择结构,如if语句,它的主要时间耗费是在执行then字句或else字句所用的时间,需注意的是检验条件也需要O(1)时间
(4)对于循环结构,循环语句的运行时间主要体现在多次迭代中执行循环体以及检验循环条件的时间耗费,一般可用大O下"乘法法则"
乘法法则: 是指若算法的2个部分时间复杂度分别为 T1(n)=O(f(n))和 T2(n)=O(g(n)),则 T1*T2=O(f(n)*g(n))
(5)对于复杂的算法,可以将它分成几个容易估算的部分,然后利用求和法则和乘法法则技术整个算法的时间复杂度
参考链接:
https://www.cnblogs.com/zknublx/p/5885840.html
https://baike.baidu.com/item/时间复杂度/1894057?fr=aladdin
https://blog.csdn.net/halotrriger/article/details/78994122#commentBox
https://www.cnblogs.com/TangBiao/p/5856695.html