使用递归式求解算法时间复杂度

本文深入解析了算法时间复杂度的概念及其计算方法,通过快排递归式的例子,详细阐述了如何利用递归来分析算法的时间复杂度,并最终计算出快排的时间复杂度为Θ(n log n)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

部分整理自:《算法导论》–机械工业出版社;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)wherenn0那么称为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_2c1n2n2+3nc2n2=>c11+n3c2
可知 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\le3c1n3n2+3nc2n3=>c1n3n2+3n=>c1n2n3 由于c1c_1c1为正,那么当n≥12c1n \ge \frac1{2c_1}n2c11, c1n2−nc_1n^2-nc1n2n 为增函数,特别地,当 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,c1n2n>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_00f(n)cg(n)wherenn0 那么称为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_00g(n)cf(n)wherenn0 那么称为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-prp 为排序的规模,那么快排序的时间递归式就可以写成:
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(rp)=T(q1p)+T(rq1)+f(rp)where f is the cost of partition
假设每次划分都能划分成相同规模的两个子规模,即 q−1−p=r−q−1=(r−p)/2q-1-p = r-q-1 = (r-p)/2q1p=rq1=(rp)/2,令 r−p=nr-p=nrp=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)+am1f(n/bm1)+...+a3f(n/b3)+a2f(n/b2)+af(n/b)+f(n)
bm=nb^m=nbm=nm=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=0logbn1ajf(n/bj)
alogbn=nlogba,T(1)=Θ(1)a^{log_b^n} = n^{log_b^a},T(1) = \Theta(1)alogbn=nlogbaT(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=0logbn1ajf(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=0log2n1n)=Θ(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

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值