部分整理自:《算法导论》–机械工业出版社;MIT的《算法导论》公开课。
#0 渐进记号(满足某种条件的函数的集合)
直接上图(自 机械工业出版社《算法导论》第三版):
(a). Θ\ThetaΘ 渐进紧确界(asymptotically tight bound)
存在正常量 n0,c1,c2n_0, c_1, c_2n0,c1,c2 使得: c1g(n)≤f(n)≤c2g(n)wheren≥n0c_1g(n) \le f(n) \le c_2g(n) \qquad where \quad n \ge n_0c1g(n)≤f(n)≤c2g(n)wheren≥n0那么称为g(n)g(n)g(n)为f(n)f(n)f(n)的渐进紧确界,记为:f(n)=Θ(g(n))f(n)=\Theta(g(n))f(n)=Θ(g(n))
例如: $f(n) = n^2 + 3n, \quad g(n) = n^2 ,则, 则,则f(n)=\Theta(g(n))=\Theta(n^2)$
c1n2≤n2+3n≤c2n2=>c1≤1+3n≤c2c_1n^2\le n^2+3n \le c_2n^2 => c_1 \le 1+\frac3n \le c_2c1n2≤n2+3n≤c2n2=>c1≤1+n3≤c2
可知 c1=1,c2=2,n0=3c_1=1,c_2=2,n_0=3c1=1,c2=2,n0=3 满足上面的不等式。
将上面的 g(n)g(n)g(n) 改成 g(n)=n3g(n)=n^3g(n)=n3,那么: c1n3≤n2+3n≤c2n3=>c1n3≤n2+3n=>c1n2−n≤3c_1n^3\le n^2+3n \le c_2n^3 => c_1n^3 \le n^2+3n=>c_1n^2-n\le3c1n3≤n2+3n≤c2n3=>c1n3≤n2+3n=>c1n2−n≤3 由于c1c_1c1为正,那么当n≥12c1n \ge \frac1{2c_1}n≥2c11, c1n2−nc_1n^2-nc1n2−n 为增函数,特别地,当 n>12c1+1+12c1,c1n2−n>3n\gt {\sqrt{12c_1+1}+1\over{2c_1}},\quad c_1n^2-n\gt3n>2c112c1+1+1,c1n2−n>3 所以f(n)≠Θ(n)f(n)\ne \Theta(n)f(n)=Θ(n)
(b) . OOO 渐进上界(asymptotically upper bound)
存在正常量 c,n0c,n_0c,n0, 使得:0≤f(n)≤cg(n)wheren≥n00\le f(n) \le cg(n) \qquad where\quad n \ge n_00≤f(n)≤cg(n)wheren≥n0 那么称为g(n)g(n)g(n)为f(n)f(n)f(n)的渐进上界,记为:f(n)=O(g(n))f(n)=O(g(n))f(n)=O(g(n))
(c) . Ω\OmegaΩ 渐进下界(asymptotically lower bound)
存在正常量 c,n0c,n_0c,n0, 使得:0≤g(n)≤cf(n)wheren≥n00\le g(n) \le cf(n) \qquad where\quad n \ge n_00≤g(n)≤cf(n)wheren≥n0 那么称为g(n)g(n)g(n)为f(n)f(n)f(n)的渐进下界,记为:f(n)=Ω(g(n))f(n)=\Omega(g(n))f(n)=Ω(g(n))
注意:有些资料上将OOO记为渐进紧确界,而在《算法导论》中OOO仅仅为渐进上界而非紧确上界,如:
n=O(n2)n=O(n^2)n=O(n2)
#1 为什么使用递归式
通常情况下,分析一段代码的时间复杂度,特别是递归调用,可以通过代码很方便地写出递归式。
partition(A,p,r)
x = A[r] // 1
i = p-1 // 1
for j = p to r-1 // 3*(r-p)
if A[j]<=x
i = i +1
exchange A[i] with A[j]
exchange A[i+1] with A[r] // 1
return i+1 //1
quick_sort(A,p,r)
if p < r
q = partition(A,p,r) //划分到子规模,规模为 r-p,代价 f(r-p)
quick_sort(A,p,q-1) //递归调用,子规模为 q-1-p, 代价 T(q-1-p)
quick_sort(A,q+1,r) //递归调用,子规模为 r-q-1, 代价 T(r-q-1)
以上为快排序代码,其中r−pr-pr−p 为排序的规模,那么快排序的时间递归式就可以写成:
T(r−p)=T(q−1−p)+T(r−q−1)+f(r−p)where f is the cost of partitionT(r-p)=T(q-1-p)+T(r-q-1)+f(r-p) \quad \text{where $f$ is the cost of $partition$}T(r−p)=T(q−1−p)+T(r−q−1)+f(r−p)where f is the cost of partition
假设每次划分都能划分成相同规模的两个子规模,即 q−1−p=r−q−1=(r−p)/2q-1-p = r-q-1 = (r-p)/2q−1−p=r−q−1=(r−p)/2,令 r−p=nr-p=nr−p=n,那么递归式可以写成这样:
T(n)=2T(n/2)+f(n)T(n)=2T(n/2)+f(n)T(n)=2T(n/2)+f(n)
由 partitionpartitionpartition 代码可以得出 f(n)=3n+4=Θ(n)f(n)=3n+4 = \Theta(n)f(n)=3n+4=Θ(n)
所以,快排序的时间递归式最终为:
T(n)=2T(n/2)+Θ(n)T(n)=2T(n/2)+\Theta(n)T(n)=2T(n/2)+Θ(n)
#2 算法时间递归式
一般情况下,算法的时间递归式都可以写成如下形式:
T(n)=aT(n/b)+f(n)T(n)=aT(n/b)+f(n)T(n)=aT(n/b)+f(n)
表示为:规模为 nnn,算法所耗费的时间等于划分时间 f(n)f(n)f(n) 加上同样算法作用在规模为 n/bn/bn/b 的时间T(n/b)T(n/b)T(n/b)的 aaa 倍。
将递归式一直写下去:T(n)=aT(n/b)+f(n)=a2T(n/b2)+af(n/b)+f(n)T(n) = aT(n/b) + f(n) = a^2T(n/b^2)+af(n/b) + f(n)T(n)=aT(n/b)+f(n)=a2T(n/b2)+af(n/b)+f(n)
T(n)=a3T(n/b3)+a2f(n/b2)+af(n/b)+f(n)T(n) = a^3T(n/b^3) + a^2f(n/b^2) + af(n/b) + f(n)T(n)=a3T(n/b3)+a2f(n/b2)+af(n/b)+f(n)
T(n)=a4T(n/b4)+a3f(n/b3)+a2f(n/b2)+af(n/b)+f(n)T(n)=a^4T(n/b^4) + a^3f(n/b^3) +a^2f(n/b^2) + af(n/b) + f(n)T(n)=a4T(n/b4)+a3f(n/b3)+a2f(n/b2)+af(n/b)+f(n)
T(n)=amT(n/bm)+am−1f(n/bm−1)+...+a3f(n/b3)+a2f(n/b2)+af(n/b)+f(n)T(n)=a^mT(n/b^m) + a^{m-1}f(n/b^{m-1}) + \quad...\quad +a^3f(n/b^3) +a^2f(n/b^2) + af(n/b) + f(n)T(n)=amT(n/bm)+am−1f(n/bm−1)+...+a3f(n/b3)+a2f(n/b2)+af(n/b)+f(n)
当 bm=nb^m=nbm=n 即 m=logbnm=log_b^nm=logbn ,子规模下降到 111, 递归式变成:
T(n)=alogbnT(1)+∑j=0logbn−1ajf(n/bj)T(n) = a^{log_b^n}T(1)+\sum_{j=0}^{log_b^n-1}a^jf(n/b^j)T(n)=alogbnT(1)+j=0∑logbn−1ajf(n/bj)
又 alogbn=nlogba,T(1)=Θ(1)a^{log_b^n} = n^{log_b^a},T(1) = \Theta(1)alogbn=nlogba,T(1)=Θ(1), 递归式变成:
T(n)=Θ(nlogba)+Θ{(∑j=0logbn−1ajf(n/bj)}.....(1)T(n)=\Theta(n^{log_b^a}) + \Theta\{(\sum_{j=0}^{log_b^n-1}a^jf(n/b^j)\}\qquad.....(1)T(n)=Θ(nlogba)+Θ{(j=0∑logbn−1ajf(n/bj)}.....(1)
证明: alogbn=nlogbaa^{log_b^n} = n^{log_b^a}alogbn=nlogba:
if:a=b>0=>loga=logb if: a = b > 0 => log^a = log^bif:a=b>0=>loga=logb
logbnlogba=logbalogbn log_b^{n^{log_b^a}} =log_b^a log_b^nlogbnlogba=logbalogbn
logbalogbn=logbnlogba log_b^{a^{log_b^n}} =log_b^n log_b^alogbalogbn=logbnlogba
#3 使用递归式计算快排序的时间复杂度
从写递归式:T(n)=2T(n/2)+Θ(n)T(n)=2T(n/2)+\Theta(n)T(n)=2T(n/2)+Θ(n)
代入式(1)得到:
=>T(n)=Θ(n)+Θ(∑j=0log2n−1n)=Θ(n)+Θ(nlog2n)=Θ(nlog2n)=Ω(nlgn)=>T(n)=\Theta(n)+\Theta(\sum_{j=0}^{log_2^n-1}n)=\Theta(n)+\Theta(nlog_2^n)=\Theta(nlog_2^n)=\Omega(nlgn)=>T(n)=Θ(n)+Θ(j=0∑log2n−1n)=Θ(n)+Θ(nlog2n)=Θ(nlog2n)=Ω(nlgn)
#4 常见函数的规模增长速度
1<lgn<n<nlgn<n2<n31 \lt lgn \lt n \lt nlgn \lt n^2\lt n^31<lgn<n<nlgn<n2<n3