一、时间复杂度
时间复杂度(Time complexity)是一个函数,它定性描述该算法的运行时间。这是一个代表算法输入值字符串长度的函数。时间复杂度常用大O表示,不包括这个函数的低阶项和首项系数。
1、 常见的时间复杂度
1) O(1)->HashMap
2) O(logn)->二叉树
3) O(n)->for循环
4) O(nlogn)->for循环嵌套二叉树
5) O(n2)->for循环嵌套for循环
2、 常见的算法时间复杂度由小到大依次为:
O(1)<O(logn)<O(n)<O(nlogn)<O(n2)<O(n3)<…<O(2n)<O(n!)
时间频度:
一个算法执行所耗费的时间,从理论上是不能算出来的,必须上机运行测试才能知道。但我们不可能也没有必要对每个算法都上机测试,只需要知道那个算法花费时间多,那个算法花费时间少就可以了。并且一个算法花费的时间与算法中语句执行次数成正比例,那个算法语句执行次数多,它花费就多。一个算法中的语句执行次数称为语气频度或时间频度。记为T(n)。
时间复杂度:
刚才提到的时间频度中,n称为问题的规模,当n不断变化时,时间频度T(n)也不断变化。但有时我们想知道它变化时呈什么规律。为此我们引入时间复杂度概念。一般情况下,算法中基本操作重复执行的次数是问题规模n的某个函数,用T(n)表示,若有某个辅助函数f(n),使得当n趋近无穷大时T(n)/f(n)的极限值为不等于零的常数,则f(n)是T(n)的同数量级函数。记做T(n)=O(f(n)),称O(f(n))为算法的渐进时间复杂度,简称时间复杂度。
时间复杂度怎么算:
基本操作即算法中的每条语句(以;号作为分割),语句的执行次数也叫做语句的频度。在做算法分析时,一般默认为考虑最坏的情况。
1) 计算出每条语句执行次数T(n)
求出代码中每条语句执行的次数。
在做算法分析时,一般默认为考虑最坏情况。
2) 计算出T(n)的数量级
求T(n)的数量级,只要将T(n)进行如下操作:
忽略常量、低次幂和高次幂系数
令f(n)=T(n)的数量级
3) 用大O来表示时间复杂度
当n趋近于无穷大时,如果lim(T(n)/f(n))的值为不等于0的常数,则称f(n)是T(n)的同数量级函数。记做T(n)=O(f(n))。
只保留最高阶项,最高阶项存在且不是1,则去除与这个项相相乘的常数。
T(n)/f(n)的极限值为不等于零的常数什么意思?
首先你要知道T(n)是f(n)忽略常量、低次幂和最高次幂的系数。只保留能代表数量级的项。
所以T(n)肯定是小于等于f(n)的
那么,如果T(n)/f(n)的极限值是等于0,那么就是说f(n)的增长趋势比T(n)大太多,那么就说明他们俩不是一个数量级的。
推导大O阶三种规则:
1) 用常数1取代运行时间中的所有加法常数
2) 只保留最高阶项
3) 去除最高阶的常数
时间复杂度是一个量级的概念,而不是具体的值,比如O(5n)的量级是n,因为这个时间复杂度函数内最高量级是变量n的一次方。
常见的时间复杂度:
1、O(1):算法复杂度和问题规模无关。换句话说,那怕你拿出几个PB的数据,我也能一步找到答案。
理论上哈希表就是O(1)。因为哈希表是通过哈希函数来映射的。所以拿到一个关键字,用哈希函数转换一下,就可以直接在表中取相应的值。和现存数据有多少毫无关系,固而每次执行该操作只需要恒定的时间(当然,实际操作存在冲突和冲突解决机制,不能保证每次取值的时间是完全一样的)。
执行次数:
N=1,大约执行1次
N=100,大约执行1次
N=1000,大约执行1次
2、对数级别O(logN):
Tips:log的底数在大O的符号中是省去的。常见的底数为2。
O(logN)算法复杂度和问题规模是对数关系。换句话说,数据量大幅增加时,消耗时间/空间只有少量增加(比如,当数据量从2增加到2^64时,消耗时间/空间只增加64倍)
执行次数:
底数为2的情况
N=10,大约执行3次
N=100,大约执行7次
N=1000,大约执行10次
N=10000,大约执行13次
3、 线性级别O(n)
算法复杂度和问题规模是线性关系。换句话说。随着样本数量的增加,复杂度也随之线性增加。
执行次数:
N=10,大约执行10次
N=100,大约执行100次
N=1000,大约执行1000次
N=10000,大约执行10000次
4、 线性对数级别O(NlogN)
for循环+二分法查找
执行次数:
N=10,大约执行33次
N=100,大约执行664次
N=1000,大约执行9966次
N=10000,大约执行132877次
5、 平方级别O(N^2)
计算的复杂度随着样本的平方数增长。如比较矬的排序,如冒泡等等。
执行次数:
N=10,大约执行100次
N=100,大约执行10000次
N=1000,大约执行1000000次
N=10000,大约执行100000000次
6、 指数级别O(2^N)
一般很难在实践中应用。
执行次数:
N=10,大约执行2^10次
N=100,大约执行2^100次
N=1000,大约执行2^1000次
N=10000,大约执行2^10000次
NlogN是比较算法里的极限了
二、空间复杂度
空间复杂度也是一个数学表达式,是对一个算法在运行过程中临时占用存储空间大小的量度 ,也就是额外占取的空间的大小。
空间复杂度不是程序占用了多少bytes的空间,因为这个也没太大意义,所以空间复杂度算的是变量的个数。
空间复杂度计算规则基本跟实践复杂度类似,也使用大O渐进表示法。
注意:函数运行时所需要的栈空间(存储参数、局部变量、一些寄存器信息等)在编译期间已经确定好了,因此空间复杂度主要通过函数在运行时候显式申请的额外空间来确定。