g(n)f(n)−cc−ε<g(n)f(n)<ε<c+ε取ε=c/2 于是,有:
c/2<g(n)f(n)<3c/2<2c
因此,∀n≥n0,有f(n)≤2cg(n),即f(n)=O(g(n))
∀n≥n0,有f(n)≥2cg(n),即f(n)=Ω(g(n))
所以:f(n)=Θ(g(n))
证毕.
传递性
设函数f,g,h的定义域为自然数集合,有:
- 如果f=O(g),且g=O(h),则f=O(h).
- 如果f=Ω(g),且g=Ω(h),则f=Ω(h).
- 如果f=Θ(g),且g=Θ(h),则f=Θ(h).
叠加性
设函数f,g,h的定义域为自然数集合,有:
如果f=O(h),g=O(h),则f+g=O(h).
其他性质
若f1(n)=O(g1(n)),f2(n)=O(g2(n)),有:
f1(n)+f2(n)f1(n)+f2(n)=O(max{g1(n),g2(n)})=O(g1(n)−g2(n))
本题摘自《算法设计与分析》陈慧南第三版第2章课后习题
常见函数的阶数比较
Tips: 在算法分析中,一般默认log()是以2为底的对数函数,即log2().
事实上在函数渐近界领域对于对数的底数因为只差一个常数系数,即有:log2n=Θ(logln)
因此,底数对分析算法复杂度上并没有影响。
阶排序
- 多项式函数的阶低于指数函数:nα=o(rn),r>1,α>0
- 对数函数的阶低于幂函数:logn=o(nα),α>0
- 阶乘:n!=o(nn);n!=ω(2n);log(n!)=Θ(nlogn)
22n>n!>n2n>2n>(23)n>nloglogn=(logn)logn>n3>n2>log(n!)=Θ(nlogn)>2logn=n>log2n>logn>logn>loglogn>n1/logn=1
取整函数的性质
- x−1<n=⌊x⌋<x<⌈x⌉=n<x+1
- ⌈x/k⌉=⌊(x+k−1)/k⌋
- ⌊x+n⌋=⌊x⌋+n,⌈x+n⌉=⌈x⌉+n
- ⌊2n⌋+⌈2n⌉=n
- ⌊b⌊an⌋⌋=⌊abn⌋,⌈b⌈an⌉⌉=⌈abn⌉
递推关系分析
设序列a0,a1,…,an,… 简记为{an}, 一个把an与某些个ai(i<n) 联系起来的等式称为关于序列{an}的递推方程,也叫递推式、递归式等。
而给定递推方程和若干个初值,计算an的通式就称为递推方程的求解。
在算法分析中,我们着重关心一个算法的时间复杂度,而时间复杂情况往往与输入数据的规模有关,我们记为T(n).
那么,如果我们能够将算法时间的递推方程描述出来,就能够用求解递推方程的相关数学方法对其进行求解了。
一般情况下,算法的时间可以用形如:
T(n)=i∑biT(li(n))+f(n)
的递推式进行刻画。
即 规模为n的问题,其时间可以用若干个规模为li(n)<n的子问题时间的线性组合,再加上非递归代价f(n)组成。
偶尔我们也会遇见非递归方程,而是不等式的形式出现的递归式,如T(n)≤T(n/2)+Θ(n)。
此时我们可以借助不等式一侧的递推关系来确定上界或下界。
下面我们将介绍求解递归式的几种常用方法,进而得到算法的Θ或O渐近界。
代入法
代入法 也叫 替代法,主要思想是通过列写几个确定 n 并且通过递推式得出的结果进行分析,猜测出对应的通式或界,最后利用数学归纳法进行证明。
该方法比较考验数学归纳的能力,但是一旦总结出来后就很容易证明。
例如:T(n)=T(n−1)+1,T(1)=1
迭代法
待更
差消法
以快速排序计算 平均时间复杂度 为例对差消法进行阐述。
假设 枢轴/基准/首元素 在一趟排序后的位置服从于均匀分布U(p,r). 即其在每一个位置的概率相等且为1/n. 那么:
情况 | 子数组的求解时间 | 子数组的求解时间 |
---|
A[1]=x | T(0) | T(n−1) |
A[2]=x | T(1) | T(n−2) |
A[3]=x | T(2) | T(n−3) |
… | … | … |
A[n]=x | T(n−1) | T(0) |
每个情况下划分时间代价的总和为n−1
于是得到平均时间代价:
T(n)⇒⇒=n1k=0∑n−1[T(k)+T(n−k)]+(n−1)=n2k=0∑n−1T(k)+(n−1)⎩⎨⎧nT(n)(n−1)T(n−1)=2k=0∑n−1T(k)+n2=2k=1∑n−2T(k)+(n−1)2nT(n)−(n−1)T(n−1)=2T(n−1)+2n−1T(n)=Θ(nlogn)
递归树|Recursion tree
Recursion Tree 将递归式转换为一棵树,树的结点表示不同层次的递归调用产生的代价,然后利用边界进行求解。
当T(n) 依赖于几个不连续的前项时,使⽤递归树解递推⽅程通常更有效。
- 递归树是迭代计算/迭代过程的模型;
- 递归树的生成过程与迭代过程⼀致;
- 递归树上所有结点恰好是迭代之后产生和式中的项;
- 对递归树上的所有结点(中间结点、叶⼦、根)求和就是迭代后方程的解。
递归树的生成过程如下:
- 初始只有根节点T(n);
- 不断地将函数项结点⽤二层子树结构替换:该子树根为T(ni),叶⼦为更小的函数项;
- 当函数项已缩小至初始值,递归树生长完成。
以二分归并排序算法为例,生成完整的递归树之后,计算每一层的代价(右边红框处),然后将它们累加起来就能得到该算法总体的时间代价了。
主定理|Master Theorem
对于递归算法,常常可以将算法规模总结为如下递归式:
T(n)=aT(n/b)+f(n)
式中,a≥1,b>1为常数,f(n)为渐近正函数,n/b可以指⌊n/b⌋ 或⌈n/b⌉
对于这类递推式的求解,可以直接利用主定理:
- 若∃ε>0,有f(n)=O(nlogba−ε),则T(n)=Θ(nlogba);
- 若f(n)=Θ(nlogba),则T(n)=Θ(nlogbalogn);
- 若∃ε>0,有f(n)=Ω(nlogba+ε),且∃c<1与所有足够大的n,有af(n/b)≤cf(n),则T(n)=Θ(f(n)).
主定理的证明
主定理的简化版本
定义h(n)=nlogba ,则主定理可以表示为:
T(n)=⎩⎨⎧Θ(h(n)),Θ(h(n)logn),Θ(f(n)),f(n)=o(h(n))f(n)=Θ(h(n))f(n)=ω(h(n))∧∃c<1s. t. af(bn)≤cf(n)
注意此处的是小o 和小ω.
参考
- 《算法导论(原书第三版)》
- 《算法设计与分析(第3版)》,陈慧南著
- 算法设计与分析|中国大学MOOC