渐进符号
O 符号
形式化定义
f(n)=O(g(n)) 表示存在常数 c>0 , n0>0 ,使得对于所有的的 n>n0 ,有
0⩽f(n)⩽cg(n)
例子:
2n2=O(n3)
直观理解
和“小于或等于”类似。去掉首项系数(此处为2)和低阶项(此处无低阶项)之后,剩下的部分小于或等于 n3
注意
O 并不是对称的。不能说 n3≠O(n2) ,甚至也不能说 O(n3)=n2
集合定义
O(g(n))={f(n):存在常数c>0,n0>0,使得对于所有的n>n0,都有0⩽f(n)⩽cg(n)}
因此,不能简单理解 2n2 与 O(n3) 是“相等”的,而应该理解为 2n2 属于函数集 O(n3) ( 2(n2)∈O(n3) )
宏
出现在公式中的集合符号(如 O )表示集合中的某一个函数,而不是集合整体。
例1: f(n)=n3+O(n2)
直观理解:表示了一个误差界限,即 f(n) 主要是由 n3 构成的,但也有一些 O(n2) 的低阶项
实际含义:存在一个函数 h(n)∈O(n2) ,使得 f(n)=n3+h(n)
例2: n2+O(n)=O(n2)
直观理解:“=”应该理解成“是”,而不是“等于”。等号左边隐含任意量词,等号右边隐含存在量词,
实际含义:对于任意函数 f(n)∈O(n) ,总存在函数 h(n)∈O(n2) ,使得 n2+f(n)=h(n)
用途: 如果有很长的“等式链”,第一个就等于最后一个(只能从左到右,因为 O 是非对称的)
Ω 符号
集合定义
Ω(g(n))={f(n):存在常数c>0,n0>0,使得对于所有的n>n0,都有0⩽cg(n)⩽f(n)}
例: n√=Ω(lgn)
直观理解: 对于充分大的 n , n√ 至少是 Ω(lgn) 的常数倍。
Θ 符号
Θ(g(n))=Ω(g(n))∩O(g(n))
例:
n2=Θ(n2)
n2+O(n)=Θ(n2)
o和ω 符号
更“严格的” O 和 Ω ,不等式需要对所有的 c 成立,而不仅仅是一个特定的c
o(g(n))={f(n):对于所有常数c>0,总存在n0>0,使得对于所有的n>n0,都有0⩽f(n)⩽cg(n)}
ω(g(n))={f(n):对于所有常数c>0,总存在n0>0,使得对于所有的n>n0,都有0⩽cg(n)⩽f(n)}
在这种情况下, n0 依赖于c
例:
2n2=O(n3)
12n2=Θ(n2)≠o(n2)≠ω(n2)
类比
O | Ω | Θ | o | ω |
---|---|---|---|---|
⩽ | ⩾ | = | < | > |
解递归式
至今为止,求解递归式还没有一种通用的方法。
代换法
- 猜出解的形式( n2 / n3… )
- 通过数学归纳法验证
- 求解常数系数
例:
T(n)=4T(n2)+n
[T(1)=Θ(1)]
观察:由 T(n)=4T(n2) 可知(忽略 n ),当 n 翻倍时, T(n) 会变为原来的4倍。
猜想: Θ(n2) (直接证明 Θ(n2) 很难,先证明 Θ(n3) )
证明 T(n)=O(n3)
- 猜想: T(n)=O(n3)
假设: k<n 时, T(k)⩽ck3
注意:代换法中不能使用 O 符号,因此需要用常数 c 来展开- 原因(较高层次):如果有一个有限项的大 O 关系序列,例如 n2=O(n3)=O(n4)=O(n4) ,由传递性可知 n2=O(n4) ,但如果大 O 关系序列是无限的,那么第一项不一定等于最后一项
例:假如想证明 n=O(1) (这显然是不对的,否则所有算法都将是常数复杂度),但却可以通过数学归纳法证明,如下:
- 1=O(1)
- 假设 n−1=O(1)
- 由于 n=(n−1)+1 ,由假设, n−1=O(1) ,且已知 1=O(1) ,所以总体是 O(1)
错误原因:证明过程中 O(1) 所代表的常数是变化的,每次 O(1) 与 O(1) 相加,都可能把 O(1) 加倍,如果是常数次的加倍,那么最终结果仍然是 O(1) ,但如果是n次加倍,结果将从 O(1) 变为 O(n)
- 结论:不能在 O 符号上进行归纳,代换法中需要用常数 c 来展开(保证不会在归纳过程中发生变化)
- 推导
T(n)=4T(n2)+n⩽4c(n2)3+n=12cn3+n=cn3−(12cn3−n)⩽cn3(if12cn3−n⩾0)当c⩾1,n⩾1时不等式成立 - 最基本的情况: T(1)=Θ(1)⩽c∗13 ,当 c⩾T(1)时成立
- 可知, T(n)=O(n3) ,但这并不是一个严格的上界,严格的上界还有可能是 O(n2) 。
证明 T(n)=O(n2)
- 猜想: T(n)=O(n2)
- 假设: k<n 时, T(k)⩽ck2
- 推导(仿照上面的过程)
T(n)=4T(n2)+n⩽4c(n2)2+n=cn2+n=cn2−(−n)⩽cn2(if(−n)⩾0)想要让(−n)非负是很难的
改进归纳假设
- 假设当 k<n 时 T(n)⩽c1k2−c2k
- 推导
T(n)=4T(n2)+n⩽4(c1(n2)2−c2(n2))+n=c1n2+(1−2c2)n=c1n2−c2n−(−1+c2)n⩽c1n2−c2n(if(c2−1)⩾0) - 最基本的情况: T(1)⩽c1−c2 ,由于 T(1)=Θ(1) ,是一个常数,因此需要 c1⩾T(1)+c2
递归树法
例: T(n)=T(n4)+T(n2)+n2