整理自极客时间-数据结构与算法之美。原文内容更完整,且有音频。购买地址:
只要讲到数据结构与算法,就一定离不开时间、空间复杂度分析。而且 我个人认为复杂度分析是真个算法的精髓,只要掌握了它,数据结构和算法的内容基本上就掌握了一半。
1.为什么需要复杂度分析?
你可能会有些疑惑,我把代码跑一遍,通过统计、监控,就能得到算法执行的时间和占用的内存大小。为什么还要做时间、空间复杂度分析呢?
首先肯定的说,这种评估算法执行效率的方法是正确的。很多书籍管这种方法叫“事后统计法”。但是这种方法有很大的局限性:
- 测试结果非常依赖测试环境:如测试环境中的硬件对测试j结果影响很大。
- 测试结果受数据规模的影响很大。如小规模的数据 插入排序反而比快速排序快。
所以,我们需要一个不用具体数据来测试,就可以粗略的估算执行效率的方法。
2.大O复杂度表示法
算法的执行效率,粗略的讲,就是算法的执行时间。
例子1:
//这里有段简单的代码,求1到n的累加和。
int cla(int n){
int sum = 0;
int i = 1;
for (;i<=n; i++){
sum = sum + 1;
}
return sum;
}
现在我们来估算下,上述代码的执行时间:
尽管每行代码对应cpu执行的个数、执行的时间都不一样,但是我们这里只是粗略的估计,所以我们可以假设每行代码执行的时间都一样,都为unit_time。在这个假设的基础上,我们进行分析!
第3、4行都执行了一次,第5、6行都执行了n次。所以这段代码总执行2*unit_time+2n*unit_time。可以看出代码的执行时间(T(n))与代码的执行次数成正比。
例2:
int cal(int n){
int sum = 0;
int i = 1;
int j = 1;
for(; i<= n ;i++){
j = 1;
for(; j <= n ; j++){
sum = sum + i*j;
}
}
}
我们依旧按照例1中的方法进行分析。
第2、3、4行代码都分别执行了一次。第5、6行都循环执行了n次,需要2n*unit_time 的执行时间。第7、8行都执行了n*n次,需要2n*n*unit_time的执行时间。 所以例2的总的执行时间为3*unit_time+2n*unit_time+2n*n*unit_time。
通过两个例子,我们可以得出一个规律:所有代码的执行时间T(n)与每行代码的执行次数n成正比。
我们可以把这个规律总结成一个公式。注意,大 O 就要登场了!
我们来解释一下这个公式。T(n)表示代码的执行时间;n表示数据规模的大小;f(n)表示每行代码执行次数的总和。因为这是一个公式,所以用f(n)表示。公式中的O,表示代码的执行时间T(n)与f(n)表达式成正比。
待续......