学习算法避不开复杂度分析,所以记录一下复杂度分析的方方面面,这篇记录基础知识。
一、为什么要用估算这种方式
分析算法复杂度,一般用BigO复杂度表示法,为什么不用机器来统计呢?原因有二:
- 机器硬件参数的不同,影响统计结果;
- 测试数据的规模大小,也会影响结果。
而BigO的估算特点,恰好可以忽视上面两条具体因素,间接做到统一标准。
二、Big O时间复杂度表示法
Big O表示的是正相关。这里指的则是:
代码总运行时间T(n)与每行代码执行次数f(n)成正比
公式为:T(n) = O(f(n))
当然T(n),f(n)不是具体的执行时间,而是:
代码执行时间随数据规模增长的变化趋势,所以,也叫作渐进时间复杂度(asymptotic time complexity),简称时间复杂度。
因此,随着数据规模变大,Big O看重的是f(n)里参数的最大量级,而低阶、常量、系数相对来说不影响总量,所以忽略。
如果f(n)参数为2n的二次方+2n+3 ,其中最大量级是n的2次方,那么n和其他常数、系数都忽略不计,这段复杂度就为:
T(n) = O(n2)
三、怎么分析时间复杂度
方法一:只看循环执行次数最多的那段代码
由于BigO看重的是f(n)里参数的最大量级,忽略低阶、常量、系数。而一段代码中,往往是循环次数最多的那一段代码量级最大,因此这段代码的量级就是要分析的时间复杂度。
方法二:加法法则,取相加后复杂度最大的那个
如果有三段代码,我们要估算这三段代码整体的时间复杂度。
第一段代码是一个常量:1000次,因此忽略。
值得注意的是就算这个常量很大,但也忽略。
尽管这会对代码的执行时间有很大影响,但是回到时间复杂度的概念来说,它表示的是一个算法执行效率与数据规模增长的变化趋势,所以不管常量的执行时间多大,我们都可以忽略掉。因为它本身对增长趋势并没有影响。
第二段代码的时间复杂度是O(n)。
第三段代码的时间复杂度是O(n2)。
这三段复杂度相加:
T(n) = n2 + n + 1000
其中n2最大,保留,忽略其他,所以最终复杂度为O(n2)。
方法三:乘法法则,嵌套代码的复杂度=嵌套内外代码复杂度的乘积
反映在代码里,则是嵌套的循环。
如果外面的循环复杂度是O(n),里面的同样是O(n),那么总的复杂度就是:
T(n) = O(n * n) = O(n2)
四、常见的复杂度量级
(按从低到高排序)
多项式量级:
- 常量级 O(1)
- 对数级 O(logn)
- 线性级 O(n)
- 线性对数级 O(n)
- 平方级 O(n2)
- 立方级 O(n3)
- K次方级 O(nk)
非多项式量级:
- 指数级 O(2n)
- 阶乘级 O(n!)
五、总结
还有空间复杂度,不过分析思路和时间复杂度一样。
可以看到复杂度分析并不难,关键还是多练习运用。