复杂度分析 是整个算法学习的精髓,只要掌握了它,数据结构和算法的内容基本上就掌握了一半。
为什么需要复杂度分析
因为事后统计法,测试的结果非常依赖测试环境,受数据规模的影响很大
所以我们需要一个不用具体的测试数据来测试,就可以粗略地估算计算法的执行效率的方法。
时间、空间复杂度分析方法
大 O 复杂度表示法
算法的执行效率,粗略地讲,就是算法代码执行的时间。
从 CPU 的角度来看,,每一行代码都执行着类似的操作:读数据-运算-写数据。尽管每行代码对应的 CPU 执行的个数、执行的时间都不一样。但是,我们这里只是粗略估计,所以可以假设每行代码执行的时间都一样,为 unit_time(单位时间)。
所有代码的执行时间 T(n)与每行代码的执行次数成正比。
执行多少次
T(n) = O(f(n))
大 O 时间复杂度实际上并不具体表示代码真正的执行时间,而是表示代码执行时间随数据规模增长的变化趋势,所以,也叫作渐进时间复杂度(asymptotic time complexity),简称时间复杂度
时间复杂度分析
忽略低阶、常量、系数
-
只关注循环执行次数最多的一段代码
-
加法法则:总复杂度等于量级最大的那段代码的复杂度
function cal(n) {
for (let i = 0, l = 100; i < l; i++) {
console.log(i);
}
for (let i = 0; i < n; i++) {
console.log(i);
}
for (let i = 0; i < n; i++) {
for (let j = 0; j < n; j++) {}
}
}
T(n) = O(max(fn(n),g(n)))
- 乘法法则:嵌套代码的复杂度等于嵌套内外代码复杂度的乘积
function cal(n){
for(let i=0;i<n;i++){
foo(i)
}
}
function foo(n){
for(let i=0,i< n;i++){
console.log(i)
}
}
T(n) = T1(n) * T2(n) = O(n*n) = O(n2)。
常见时间复杂度分析
-
常量阶(O(1))
-
对数阶(O(logn))
-
线性阶(O(n))
-
线性对数阶(O(n))
-
平方阶(O(n^2)) 、 立方阶(O(n^3)cdots) k 次方阶(O(n^k))
-
指数阶(O(2^n))
-
阶乘阶(O(n!))
对于复杂度量级,可以粗略分为两类,多项式量级和非多项式量级。其中非多项式量级只有两个(O(2^n))和(O(n!))
最好、最坏、平均、均摊情况时间复杂度
最好情况时间复杂度(best case time complexity)
在理想的情况下,执行这段代码的时间复杂度
最坏情况时间复杂度(worst case time complexity)
在最糟糕的情况下,执行这段代码的时间复杂度
平均情况时间复杂度(average case time complexity)
均摊时间复杂度(amortized time complexity)
对一个数据结构进行一组连续操作中,大部分情况下时间复杂度都很低,只有个别情况下时间复杂度比较高,而且这些操作之间存在前后连贯的时序关系,这个时候,我们就可以将这一组操作放在一块儿分析,看是否能将较高时间复杂度那次操作的耗时,平摊到其他那些时间复杂度比较低的操作上。而且,在能够应用均摊时间复杂度分析的场合,一般均摊时间复杂度就等于最好情况时间复杂度。
数学知识
对数
换底公式
数列
等差数列
概率
概率乘法