递归方程时间复杂度分析

递归算法的时间复杂度分析

一个认识递归问题的小例子

首先使用一个简单的案例看一下递归方程的时间复杂度分析。
假设有以下的简单算法:

int Sort(int i,int j)
{
	if(i==j)
		return(x[i]);
	else
	{
		m = (i + j - 1)/2;
		return(Merge(Sort(i,m),Sort(m + 1,j)));
	}
}

x x x是一个数组,如果设输入的是 n n n, Sort在最坏的情况下的运行时间是 T ( n ) T(n) T(n),那么 T ( n ) T(n) T(n)可以写成如下的迭代式:
T ( n ) ≤ { c 1 , n = 1 2 T ( n 2 ) + c 2 n , n > 1 T(n) \le \begin{cases} c_1,n=1\\ 2T(\frac{n}{2})+c_2n, n>1\end{cases} T(n){c1n=12T(2n)+c2nn>1
n = 1 n=1 n=1时,算法的运行时间就是常数。而当 n > 1 n>1 n>1时,算法的运行时间可以进一步细分为进一步进行两个Sort的时间,此时的 n n n已经变成了 n 2 \frac{n}{2} 2n。除此之外,还有判断 i = = j i==j i==j和划分 m m m以及Merge函数带来的时间消耗,我们使用一个常数 c 2 n c_2n c2n来作为Sort中除递归以外其它时间开销的上界,至于使用 c 2 n c_2n c2n而不是 c 2 c_2 c2,是因为Merge函数的时间复杂度是正比于 n n n的(这一步是基于题目假设的,如果在其它的递归问题中,这个后缀项是可以变化的)。

至此,我已经给出了一个简单递归例子的递归方程,所有的递归问题都可以简化写成如此的一个方程,为了方便后续分析递归问题 ,我们可以给出这种迭代方程的通项公式:

一类递归方程的展开式通解
T ( n ) T(n) T(n)是某个问题的时间开销, n n n是该问题的规模,设对此问题列出的递归方程为:
T ( n ) = { 1 , n = 1 a T ( n / c ) + d ( n ) , n > 1 ( 1 ) T(n) = \begin{cases} 1,n=1\\ aT(n/c)+d(n), n>1\end{cases} (1) T(n)={1n=1aT(n/c)+d(n)n>1(1)
其中 c c c是大于1的正整数。全部的数据被分割成 c c c等份,每份的数量为 n / c n/c n/c T ( n / c ) T(n/c) T(n/c)是求解一个子问题的时间开销。 a T ( n / c ) aT(n/c) aT(n/c)代表求解 a a a个子问题时间的开销。 d ( n ) d(n) d(n)是任意的函数,因此方程是严格的等式。

递归问题的时间分析

在上一节中,我们给出了递归方程的通项公式,但是并没有给出通项公式的解,下面是求解 T ( n ) T(n) T(n)的详细步骤。
使用 n / c i n/c^i n/ci代替式子(1)中的 n n n,得到:
T ( n c i ) = a T ( n c i + 1 ) + d ( n c i ) ( 2 ) T(\frac{n}{c^i}) = aT(\frac{n}{c^{i+1}}) + d(\frac{n}{c^i}) (2) T(cin)=aT(ci+1n)+d(cin)2
由式(1)开始,将(2)代入(1)得到:
T ( n ) = a T ( n c ) + d ( n ) = a ( a T ( n c 2 ) + d ( n c ) ) + d ( n ) = a 2 T ( n c 2 ) + a d ( n c ) + d ( n ) = a i T ( n c i ) + ∑ j = 0 i − 1 a j d ( n c j ) \begin{aligned} T(n) &= aT(\frac{n}{c}) + d(n)\\ &= a(aT(\frac{n}{c^2})+d(\frac{n}{c}))+d(n) \\ &=a^2T(\frac{n}{c^2}) + ad(\frac{n}{c}) + d(n)\\ &=a^iT(\frac{n}{c^i}) + \sum_{j=0}^{i-1}a^jd(\frac{n}{c^j}) \end{aligned} T(n)=aT(cn)+d(n)=a(aT(c2n)+d(cn))+d(n)=a2T(c2n)+ad(cn)+d(n)=aiT(cin)+j=0i1ajd(cjn)
假设 n = c k n=c^k n=ck,则 T ( n / c k ) = T ( 1 ) = 1 T(n/c^k) = T(1) = 1 T(n/ck)=T(1)=1。令 i = k i = k i=k,有:
T ( n ) = a k + ∑ j = 0 k − 1 a j d ( c k − j ) ( 3 ) T(n) = a^k + \sum_{j = 0}^{k-1}a^jd(c^{k-j})(3) T(n)=ak+j=0k1ajd(ckj)3
n = c k n=c^k n=ck可以推出 k = l o g c n k = log_cn k=logcn,则上式的第一项可以写成 a l o g c n a^{log_cn} alogcn,同时也可以写成 n l o g c a n^{log_ca} nlogca。下面给出了这个等价的证明

证明 n l o g c a n^{log_ca} nlogca = a l o g c n a^{log_cn} alogcn
t = l o g c a t = log_ca t=logca,则 c t = a c^t = a ct=a,左边等于 n t n^t nt,右边是 ( c t ) l o g c n = c t l o g c n = c l o g c n t = n t (c^t)^{log_cn} = c^{t log_cn} = c^{log_cn^t} = n^t (ct)logcn=ctlogcn=clogcnt=nt,所以左边等于右边。

上式的 n l o g c a 是 n^{log_ca}是 nlogca d ( n ) d(n) d(n)恒为0时的解,称为齐次解。齐次解代表求解所有子问题的时间开销,而第二项称为特解,特解主要是对问题数据的分割和处理,以及建立子问题所消耗的时间,还包括合并所有子问题求解结果等所花费的时间。

针对一个递归问题,我们要做的就是计算(3)式的时间复杂度,第一项是 n l o g c a n^{log_ca} nlogca,第二项是我们需要考虑的,由于第二项存在一个抽象函数 d ( n ) d(n) d(n),因此我们需要对 d ( n ) d(n) d(n)的情况进行分类讨论,从而确定递归函数的通解情况。

递归函数特解情况分类讨论

倍积函数

如果 d ( n ) d(n) d(n)满足倍积函数性质,则有对所有正整数 x , y x,y x,y,有 f ( x y ) = f ( x ) f ( y ) f(xy) = f(x)f(y) f(xy)=f(x)f(y),就是说 f f f是正整数上的倍积函数。在上面的式子(3)中,现预定 d ( n ) d(n) d(n)是倍积函数,因此满足 d ( c k − j ) = ( d ( c ) ) k − j d(c^{k-j}) = (d(c))^{k-j} d(ckj)=(d(c))kj
由此(3)式中的特解可以写为:
∑ j = 0 k − 1 a j d ( c k − j ) = ∑ j = 0 k − 1 a j ( d ( c ) ) k − j = ( d ( c ) ) k ∑ j = 0 k − 1 ( a d ( c ) ) j = a k − ( d ( c ) ) k a d ( c ) − 1 ( 4 ) \begin{aligned} \sum_{j = 0}^{k-1}a^jd(c^{k-j})& = \sum_{j = 0}^{k-1}a^j(d(c))^{k-j}\\ &= (d(c))^k\sum_{j = 0}^{k-1}(\frac{a}{d(c)})^j \\ &=\frac{a^k-(d(c))^k}{\frac{a}{d(c)}-1}(4) \end{aligned} j=0k1ajd(ckj)=j=0k1aj(d(c))kj=(d(c))kj=0k1(d(c)a)j=d(c)a1ak(d(c))k4
到此可以看出规律,我们可以给出下面的定理:

a 、 c a、c ac是非负常数, n n n是2的幂, d ( n ) d(n) d(n)是倍积函数,则
T ( n ) = { b , n = 1 a T ( n / c ) + d ( n ) , n > 1 ( 1 ) T(n) = \begin{cases} b,n=1\\ aT(n/c)+d(n), n>1\end{cases} (1) T(n)={bn=1aT(n/c)+d(n)n>1(1)
的齐次解是 O ( n l o g c a ) O(n^{log_ca}) O(nlogca),且对特解有如下结论(设 k = l o g c n k = log_cn k=logcn)。
一、若 a > d ( c ) a>d(c) a>d(c),则特解是 O ( a k ) O(a^k) O(ak) O ( n l o g c a ) O(n^{log_ca}) O(nlogca),即特解与齐次解同阶。
二、若 a < d ( c ) a<d(c) a<d(c),则特解是 O ( ( d ( c ) ) k ) O((d(c))^k) O((d(c))k) O ( n l o g c d ( c ) ) O(n^{log_cd(c)}) O(nlogcd(c)),即特解与 d d d同阶。
三、若 a = d ( c ) a = d(c) a=d(c), 则特解是其次解的 l o g c n log_cn logcn倍。

上述三个结论的证明很简单,前两个只需要对(4)式进行分析即可,若 a > d ( c ) a>d(c) a>d(c),那么按照计算时间复杂度来说特解是 O ( a k ) O(a^k) O(ak),即与齐次解相同,那么此时的递归算法的整体时间复杂度是 O ( a k ) O(a^k) O(ak) O ( n l o g c a ) O(n^{log_ca}) O(nlogca)
对于三、我们不能从(4)中分析,可以这么分析:

∑ j = 0 k − 1 a j ( d ( c ) ) k − j = ( d ( c ) ) k ∑ j = 0 k − 1 ( a d ( c ) ) j = ( d ( c ) ) k ∑ j = 0 k − 1 1 = ( d ( c ) ) k × k = ( d ( c ) ) l o g c n × l o g c n = n l o g c d ( c ) × l o g c n \sum_{j = 0}^{k - 1}a^j(d(c))^{k-j} = (d(c))^k\sum_{j = 0}^{k-1}(\frac{a}{d(c)})^j = (d(c))^k\sum_{j = 0}^{k - 1}1 = (d(c))^k×k = (d(c))^{log_cn}×log_cn = n^{log_cd(c)}×log_cn j=0k1aj(d(c))kj=(d(c))kj=0k1(d(c)a)j=(d(c))kj=0k11=(d(c))k×k=(d(c))logcn×logcn=nlogcd(c)×logcn

因此对于不同的参数 a a a d ( c ) d(c) d(c),我们能分类讨论。
下面针对倍积函数,列举了几个例子。

设有三个方程。当 n ≥ 2 n\ge 2 n2时,它们分别满足下面的式子,当 n = 1 n = 1 n=1时, T ( 1 ) = 1 T(1) = 1 T(1)=1
1、 T ( n ) = 4 T ( n / 2 ) + n T(n) = 4T(n/2) + n T(n)=4T(n/2)+n
2、 T ( n ) = 4 T ( n / 2 ) + n 2 T(n) = 4T(n/2) + n^2 T(n)=4T(n/2)+n2
3、 T ( n ) = 4 T ( n / 2 ) + n 3 T(n) = 4T(n/2) + n^3 T(n)=4T(n/2)+n3
由于 a a a c c c的值是不变的, a = 4 a = 4 a=4 c = 2 c = 2 c=2.因此只需要分析 d ( n ) d(n) d(n)即可。
齐次解 n l o g c a = n 2 n^{log_ca} = n^2 nlogca=n2
对1来说, d ( n ) = n d(n) = n d(n)=n, a > d ( c ) a>d(c) a>d(c),特解与齐次解同阶,因此 T ( n ) = O ( n 2 ) T(n) = O(n^2) T(n)=O(n2).
对2来说, d ( n ) = n 2 d(n) = n^2 d(n)=n2, a = d ( c ) a = d(c) a=d(c),特解是齐次解的 l o g c n log_cn logcn倍,因此 T ( n ) = O ( n 2 l o g n ) T(n) = O(n^2logn) T(n)=O(n2logn).
对3来说, d ( n ) = n 3 d(n) = n^3 d(n)=n3, a < d ( c ) a < d(c) a<d(c),特解与 d d d同阶,因此 T ( n ) = O ( n 3 ) T(n) = O(n^3) T(n)=O(n3).

倍积函数与常数之积

d ( n ) d(n) d(n)是常数与倍积函数之积时,我们可以通过转化的方法将其化简为倍积的情况,下面是一个例子。
设有
T ( n ) = { 1 , n = 1 3 T ( n 2 ) + 2 n 1.5 , n > 1 T(n) = \begin{cases} 1,n=1\\ 3T(\frac{n}{2})+2n^{1.5}, n>1\end{cases} T(n)={1n=13T(2n)+2n1.5n>1
2 n 1.5 2n^{1.5} 2n1.5不是倍积函数,但是 n 1.5 n^{1.5} n1.5却是。我们令 U ( n ) = T ( n ) / 2 U(n) = T(n)/2 U(n)=T(n)/2,则得到
{ U ( 1 ) = 1 / 2 U ( n ) = 3 U ( n / 2 ) + n 1.5 \begin{cases} U(1) = 1/2\\ U(n) = 3U(n/2) + n^{1.5}\end{cases} {U(1)=1/2U(n)=3U(n/2)+n1.5
其齐次解是 n l o g 2 3 = n 1.59 n^{log_23} = n^{1.59} nlog23=n1.59,所以 T ( n ) T(n) T(n)的齐次解是 n 1.59 / 2 n^{1.59}/2 n1.59/2,仍然是 O ( n 1.59 ) O(n^{1.59}) O(n1.59)
对于特解来说,由于 a = 3 , c = 2 , d ( n ) = n 1.5 , d ( c ) = c 1.5 = 2.82 < a a = 3,c = 2,d(n) = n^{1.5},d(c) = c^{1.5} = 2.82<a a=3,c=2,d(n)=n1.5,d(c)=c1.5=2.82<a,所以关于 U ( n ) U(n) U(n)的特解也是 O ( n 1.59 ) O(n^{1.59}) O(n1.59)。最终 T ( n ) T(n) T(n)也是 O ( n 1.59 ) O(n^{1.59}) O(n1.59)
从这个例子中能看出,对于常数与倍积函数相乘的情况,我们可以先进行化简,使得其成为倍积函数的情况。

其它非倍积函数

d ( n ) d(n) d(n)为非倍积函数又无法进行变化时,只得对
∑ j = 0 k − 1 a j d ( c k − j ) \sum_{j = 0}^{k-1}a^jd(c^{k-j}) j=0k1ajd(ckj)进行运算,进而求出特解得紧凑上界。下面也是一个例子。
设有:
T ( n ) = { 1 , n = 1 2 T ( n 2 ) + n l o g n , n > 1 T(n) = \begin{cases} 1,n=1\\ 2T(\frac{n}{2})+nlogn, n>1\end{cases} T(n)={1n=12T(2n)+nlognn>1
a = c = 2 a = c = 2 a=c=2,易知齐次解是 n l o g c a = n n^{log_ca}= n nlogca=n,但是 d ( n ) = n l o g n d(n) = nlogn d(n)=nlogn并不是倍积函数,无法使用定理来处理,因此需要其它的方法。
我们可以直接对级数求和,有
∑ j = 0 k − 1 a j d ( c k − j ) = ∑ j = 0 k − 1 2 j × 2 k − j × l o g 2 k − j = 2 k ∑ j = 0 k − 1 ( k − j ) = 2 k − 1 × k ( k + 1 ) \begin{aligned} \sum_{j = 0}^{k-1}a^jd(c^{k-j})& = \sum_{j= 0}^{k-1}2^j ×2^{k-j}×log{2^{k-j}} \\&= 2^k\sum_{j = 0}^{k-1}(k-j)\\ & = 2^{k - 1} ×k(k+1)\end{aligned} j=0k1ajd(ckj)=j=0k12j×2kj×log2kj=2kj=0k1(kj)=2k1×k(k+1)

由于我们前面令的 k = l o g n k = logn k=logn,因此特解的时间是 O ( n l o g 2 n ) O(nlog2^n) O(nlog2n),特解是大于齐次解的,因此特解是 T ( n ) T(n) T(n)的最终的时间复杂度。(这里为什么特解的时间是 O ( n l o g 2 n ) O(nlog2^n) O(nlog2n)我并没有验算,应该就是把 k k k代入到最终的化简式中分析)。

总结

  到这里所有有关递归算法的简单分析都已经结束了,针对一个递归问题,首先可以将其使用数学递推式表示出来,根据后缀项的情况进行分类讨论,可以分为倍积、倍积常数和其它。
  当 d ( n ) d(n) d(n)是倍积项时,不需要进行计算,直接使用定理即可,通过简单的比较 a 与 d ( c ) a与d(c) ad(c)的大小关系来确定最终 T ( n ) T(n) T(n)的时间复杂度。当 a > d ( c ) a>d(c) a>d(c)时,特解与齐次解同阶;当 a = d ( c ) a = d(c) a=d(c)时,特解是齐次解的 l o g c n log_cn logcn倍;当 a < d ( c ) a<d(c) a<d(c)时,特解与 d d d同阶。齐次解是 n l o g c a n^{log_ca} nlogca
  当 d ( n ) d(n) d(n)是倍积乘常数时,需要先进行化简,化简为能使用定理处理的情况。当 d ( n ) d(n) d(n)是其它情况时,可以直接代入级数项求和,根据求出的结果和齐次解进行比较从而再确定。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值