复杂度分析的意义:在写代码时更快速的理解和估算当前代码的时间复杂度与空间复杂度,根据这两个分析能对自己这段代码的运行速度与内存占用进行优化。(这两个指标经常出现在leetcode中,来检验自己的代码质量)
渐进时间复杂度(asymptotic time complexity),简称时间复杂度:代码的执行时间随着数据规模增长的变化趋势。
例如,当一段代码T(n) = O(2n+2)时,因为他表示的知识一种变化趋势,所以系数和常量等都可以被忽略,只用记录一个最大阶的量级就行。即T(n) = O(n),代表这段代码的时间随着数据集的增长呈现一个n的线性增长。其中,T(n)表示执行时间,n表示数据规模的大小,大O是它的复杂度。
渐进空间复杂度(asymptotic space complexity),简称空间复杂度:代码的存储空间随着数据规模增长的变化趋势。
空间复杂度的分析方法与时间复杂度类似,并且比时间复杂度分析要简单很多。具体分析,是看一段代码中有哪些关于n的空间存储变量。比如,int[n],空间复杂度为O(n)。
时间复杂度分析三条原则:
1.一般只关注最大阶的量级,也就是说关注循环执行次数最多的那一段代码。
如果整段代码只有循环一次,就是O(n)。
如果整段有循环嵌套循环和一些普通循环,它会忽略普通的O(n),最终复杂度为O(n^2)。(这条同时运用了第二条加法法则)
2.加法法则:总复杂度等于量级最大的那段代码的复杂度
3.乘法法则:嵌套代码的复杂度等于嵌套内外代码复杂度的乘积
如果一段代码里有两个复杂度为O(n)的函数,那么T(n)=T1(n)*T2(n)=O(f(n))*O(g(n))=O(f(n)*g(n))
常见时间复杂度量级:
这些常见的复杂度量级,我们可以分为两类,多项式量级和非多项式量级。非多项式量级是右边划线的两种,指数阶和阶乘阶。这种算法问题叫做NP(Non-Deterministic Polynomial,非确定多项式)问题。NP问题的执行时间会随数据量急剧增加,是非常低效的算法。
NP问题:能够在多项式问题(P问题)的时间内,验证该问题的一个正确解的问题。
根据定义可以看出来,NP问题的确比P问题要复杂不少,我们只能在解决P问题的时间内能验证它的其中一个解是否正确。而比NP问题更复杂的问题也是存在的,这里就不作展开了。(其实是我自己也搞不懂,有兴趣的可以自行查阅)
常见时间复杂度量级分析:
1. O(1)
int i = 8;
int j = 6;
int sum = i + j;
2. O(logn)、O(nlogn)
i=1;
while (i <= n) {
i = i * 2;
}
我们可以根据代码得出,i相当于一个2的等比数列,所以当2^x>n时,代码结束运行,它执行了x次。x=log2(n),所以O(logn).
O(nlogn),可看做是n*logn的一段嵌套代码。
不同复杂度量级的增长趋势:
最好情况时间复杂度(best case time complexity):
在最理想的情况下,执行这段代码所需的时间复杂度。
比如,需要在一个数组中寻找一个数,最幸运的情况是,找的第一个数字就是要寻找的。这时,大O为O(1)。
最坏情况时间复杂度(worst case time complexity):在最差的情况下,执行这段代码所需的时间复杂度。
还是刚才在数组中查找的例子,我们遍历了所有数后才得到要找的数字。这时,大O为O(n)。
平均情况时间复杂度(average case time complexity):把可能发生的情况(概率)和他们对应的时间复杂度都分析出来,然后计算他们的加权平均值。
均摊时间复杂度(amortized time complexity):把可能发生的情况和可能存在的事件发生时间顺序及时间复杂度大概分析出来,然后根据可能出现多的情况估算。
知道以上四个数据的意义:为了能更全面的理解和估算当前算法。就像面对一堆样本数据,需要知道他们的平均值,中位数,众数等信息来对该数据集建立一个大致的认知模型一样。实际运用中,并不要求把每个算法的这四个值都算出来,而他们运算的时候也没有那么严格的要求。(考试除外2333)
复杂度分析的实际运用意义和认知:
看到了一位大神对于复杂度分析的看法,我觉得特别有道理,对于复杂度的认知又更进了一步,在此引用一下:
“渐进式时间,空间复杂度分析只是一个理论模型,只能提供给粗略的估计分析,我们不能直接断定就觉得O(logN)的算法一定优于O(n), 针对不同的宿主环境,不同的数据集,不同的数据量的大小,在实际应用上面可能真正的性能会不同。
但是,渐进时间,空间复杂度分析为我们提供了一个很好的理论分析的方向,并且它是宿主平台无关的,能够让我们对我们的程序或算法有一个大致的认识,让我们知道,比如在最坏的情况下程序的执行效率如何,同时也为我们交流提供了一个不错的桥梁,我们可以说,算法1的时间复杂度是O(n),算法2的时间复杂度是O(logN),这样我们立刻就对不同的算法有了一个“效率”上的感性认识。”
总结就是,虽然复杂度分析在实际生产应用时,不一定是最准确的,但是具有这种思维,能在最快的情况下,让我们对于当前的代码有一个大概的认知,利于我们去比较大部分通用情况下不同代码的效率。
网友评论