复杂度分析
$O(1)$
- 分类:一般地,仅含一次或常数次基本操作的算法
此类算法通常不含循环,分支,子程序调用 - 效率最高
$O((logn)^c)$
- 不必写出 $\log$ 的底数,因为 $\log_{a}{n} = \log_{a}{b} \cdot \log_{b}{n}$
同理常数次幂不必写,因为 $\log_{a}{n^c} = c\log_{a}{n}$
对数多项式类型的复杂度可以忽略低次项 - 复杂度无限接近于常数,效率第二高
$O(n^c)$
- $n$ 的多项式类型的复杂度可以忽略所有低次项
- $O(n) \sim O(n^2)$是编程习题主要覆盖的范围
- 效率第三高,比较令人满意
$O(2^n)$
- 成本增长快,难解
- $O(n^c) \rightarrow O(2^n)$ 是从有效算法 $\rightarrow$ 无效算法的分水岭
- 某些问题算法最优解就是 $O(2^n)$ 了,不存在 $O(n^c)$ 的算法
如 2-Subset 问题就是 NP-complete
算法分析
- 任务:正确性(不变性 && 单调性) + 复杂度
- 复杂度分析的主要方法
- 迭代:级数求和
- 递归:递归跟踪 + 递推方程
- 猜测 + 验证
级数
- 算数级数:与末项平方同阶
$$T(n) = 1+2+3+…+n = \frac{n(n+1)}{2} = O(n^2) $$
- 幂级数:比幂次高一阶
$$T(n) = 1^c+2^c+ … +n^c = O(n^{c+1})$$
- 等比级数:与末项同阶
$$T(n) = a^0+a^1+a^2+…+a^n = O(a^n)$$
- 收敛级数
$$T(n) = O(1)$$
- 调和级数
$$T(n) = 1+\frac{1}{2}+\frac{1}{3}+…+\frac{1}{n} = \Theta(logn)$$
- 对数级数
$$T(n) = log1+log2+…+logn = log(n!) = \Theta(nlogn)$$
循环
- 二重循环(1)的复杂度 (类比 j-i 坐标系中矩形的面积)
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
O1Operation(i, j);
}
}
$$T(n) = \sum_{i=0}^{n-1}n = n \times n = O(n^2)$$
- 二重循环(2)的复杂度 (类比 j-i 坐标系中三角形的面积)
for (int i = 0; i < n; i++) {
for (int j = 0; j < i; j++) {
O1Operation(i, j);
}
}
$$T(n) = \sum_{i=0}^{n-1}i = 0+1+…+(n-1) = \frac{n(n-1)}{2} = O(n^2)$$
- 二重循环(3)的复杂度 (类比 $\frac{j}{c}$-i 坐标系中三角形的面积)
for (int i = 0; i < n; i++) {
for (int j = 0; j < i; j += c) {
O1Operation(i, j);
}
}
$$T(n) = O(n^2)$$
- 二重循环(4)的复杂度 (几何级数)
for (int i = 1; i < n; i *= 2) {
for (int j = 0; j < i; j ++) {
O1Operation(i, j);
}
}
$$T(n) = 1+2+4+…+2^{\log_{2}{n-1}} = \sum_{k=0}^{\log_{2}{(n-1)}}2^k (let \ k = \log_{2}{i})= O(n)$$
- 二重循环(5)的复杂度 (几何级数)
for (int i = 0; i < n; i ++) {
for (int j = 1; j < i; j += j) {
O1Operation(i, j);
}
}
$$T(n)=0+0+1+2 \times 2+3 \times 4+4 \times 8…=\sum_{k=0…logn}^{}(k \cdot 2^{k-1})=O(\log_{}{n} \cdot2^{\log_{}{n}})=O(n\log_{}{n})$$