《Mathematical Analysis of Algorithms》中有关“选择第t大的数”的算法分析
Posted allegro-vivace
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《Mathematical Analysis of Algorithms》中有关“选择第t大的数”的算法分析相关的知识,希望对你有一定的参考价值。
开头废话
这个问题是Donald.E.Knuth在他发表的论文Mathematical Analysis of Algorithms中提到的,这里对他的算法分析过程给出了更详细的解释。
问题描述:
给定一个数组a[1,2,...,n],用尽量少的比较次数找出数组中第t大的数。(假定这n个数两两不同)。
算法描述:
对于这个问题,可以很容易想到对应的算法。一个 (O(nlog n)) 的排序算法总能解决问题(然鹅今天我们并不对数组进行完全的排序)。
参照快速排序中的Partition操作,将元素a[i]放到某个位置(k),使得排在它前面的元素都比它大(但不一定按照从大到小的次序排列),后面的元素都比它小。再根据a[i]的位置(k)与(t)的大小关系,缩小查找范围再对子问题求解。
对于每一次Partition操作,会有这样的3种情况:
(1).若(k=t),算法结束。
(2).若(k>t),则对a[i]~a[k-1]递归地求解
(3).若(k<t),则对a[k+1]~a[j]递归地求解
时间复杂度分析
在这个问题的求解过程中,产生子问题的规模不断缩小。其中影响子问题的变量有(n)(数组的长度)和(t)(待查找的t)。Knuth记(C_{n,t})为在(n)个元素的数组中选择第(t)大的数所需的平均比较次数,这里有一个前提,我们假设数组的排列是随机的,每一次Partition找到第1,第2,...,第n大的数概率均为(frac 1 n)。
于是我们可以得到这样的式子:
[
egin {aligned}
C_{1,1}&=0C_{n,t}&=n-1+frac 1n (A_{n,t}+B_{n,t}+0)
end {aligned}
]其中(A_{n,t})和(B_{n,t})的定义如下:[
egin {aligned}
A_{n,t}&=C_{n-1,t-1}+C_{n-2,t-2}+cdots+C_{n-t+1,1}B_{n,t}&=C_{t,t}+C_{t+1,t}+cdots+C_{n-1,t}
end {aligned}
]这里(A_{n,t})对应的是递归过程中所有(k<t)的情况。对于这些情况,我们从数组的第(k+1)项开始向后的部分进行求解,如果把这部分看作一个新的数组,那么原始数组中第(t)大的数,在新的数组中是第(t-k)大的,也就是说这部分子问题是查找长度为(n-k)的数组中第(t-k)大的元素,其中(1leq k leq n.)
类似的,(B_{n,t})对应所有(k>t)的情况,将数组第一项到第(k-1)项取出,看作一个新的数组,原始数组中第(t)大的数,在这新的数组中仍然是第(t)大,所以这部分的子问题是在长度为(k-1)的数组中选择第(t)大的数,其中(t+1leq k leq n.)
括号内剩下的一项(0),对应的是(k=t)的情况,因为此时算法结束,不需要再求解子问题,所以比较次数为(0.)括号外的(n-1)是一次Partition要进行的比较次数。
这样,括号内就等于所有可能规模子问题的比较次数的总和,将它乘以(frac 1n),就得到子问题比较次数的数学期望,即我们所求的平均情况下的预期比较次数。
通过观察我们可以得到以下的递推公式:
[
egin {aligned}
A_{n+1,t+1}&=C_{n-1,t-1}+C_{n-2,t-2}+cdots+C_{n-t+1,1}+C_{n,t}=A_{n,t}+C_{n,t}B_{n+1,t}&=C_{t,t}+C_{t+1,t}+cdots+C_{n-1,t}+C_{n+1-1,t}=B_{n,t}+C_{n,t}
end{aligned}
]由上述等式作差消法,可以得到:
[
(n+1)C_{n+1,t+1}-nC_{n,t+1}-nC_{n,t}+(n-1)C_{n-1,t}=(n+1)n-n(n-1)-n(n-1)+(n-1)(n-2)\+(A_{n+1,t+1}-A_{n,t})-(A_{n,t+1}-A_{n-1,t})+(B_{n+1,t+1}-B_{n,t+1})-(B_{n,t}-B_{n-1,t})
=2+C_{n,t}-C_{n-1,t}+C_{n,t+1}-C_{n-1,t}
]合并同类项即可得到:
[
(n+1)C_{n+1,t+1}-(n+1)C_{n,t+1}-(n+1)C_{n,t}+(n+1)C_{n-1,t}=2\DownarrowC_{n+1,t+1}-C_{n,t+1}-C_{n,t}+C_{n-1,t}=frac{2}{n+1}
]
接下来我们考察边界条件,当(t=1)时,由以上的式子我们可以得到下述方程组:
[
left{
egin{array}{l}
C_{n,1}= n-1+frac{1}{n}(C_{1,1}+C_{2,1}+cdots +C_{n-1,1}) B_{n,1}=C_{1,1}+C_{2,1}+cdots+C_{n-1,1} B_{n+1,1}=B_{n,1}+C_{n,1} C_{n,1}=n-1+frac{1}{n}(B_{n,1}) C_{n+1,1}=n+frac{1}{n+1}(B_{n+1,1})
end{array}
ight.
]消去方程组中包含(B)的项,可以得到:
[
egin{aligned}
(n+1)C_{n+1,1}-nC_{n,1} &= (n+1)n-n(n-1)+C_{n,1}C_{n+1,1}-C_{n,1}&=2-frac{2}{n+1} quadquad(*)
end{aligned}
]接下来求解(C_{n,1}):
列出方程组:
[
left{
egin{array}{c}
egin{aligned}
C_{1,1}&=0C_{2,1}-C_{1,1}&=2-frac22C_{3,1}-C_{2,1}&=2-frac23\cdotsC_{n,1}-C_{n-1,1}&=2-frac2n\end{aligned}
end{array}
ight.\]将以上(n)个方程求和,最终左边只剩下(C_{n,1}),得到如下式子:
[
egin{aligned}
C_{n,1}&=2(n-1)-2sum_{k=2}^n frac1k\quadDownarrow
C_{n,1}&=2n-2sum_{k=1}^nfrac1k=2n-2H_n
end{aligned}
]这里的(H_n)表示调和级数的前(n)项部分和。
由于问题具有的对称性(这部分可自行证明),(C_{n,n}=C_{n,1}=2n-2H_n),将此式记作((Delta))
由((*))式,可以列出以下方程组:
[
left{
egin{array}{l}
(C_{n+1,t+1}-C_{n,t})-(C_{n,t+1}-C_{n-1,t})=frac2{n+1}(C_{n,t+1}-C_{n-1,t})-(C_{n-1,t+1}-C_{n-2,t})=frac2{n}\quadquadquadquadquadquadquadquadcdots(C_{t+2,t+1}-C_{t+1,t})-(C_{t+1,t+1}-C_{t,t})=frac2{t+2}\end{array}
ight.\]再次对这(n-t)个方程累加,并联立((Delta))式,可以得到:
[
egin{aligned}
C_{n+1,t+1}-C_{n,t}&=frac{2}{n+1}+frac{2}{n}+cdots+frac{2}{t+2}+C_{t+1,t+1}-C_{t,t}&=2(H_{n+1}-H_{t+1})+2-frac{2}{t+1}
end{aligned}
]依次写出(C_{n,t}-C_{n-1,t-1})到(C_{2,2}-C_{1,1})的(n-1)个方程并再次累加(过程略去),可以推出:
[
C_{n,t}=2sum_{2leq kleq t}(H_{n-t+k}-H_{k}+1-frac1k)+C_{n+1-t,1}
]
化简后:
[
C_{n,t}=2((n+1)H_n-(n+3-t)H_{n+1-t}-(t+2)H_t+n+3),quad(1leq tleq n)
]
由于(t)与(n)同阶,且平均情况下(t)的数学期望(E(t)=frac 2n),又 (H_n=Theta(log n)) ,所以:
[
C_{n,t}=O(nlog n)
]至此,时间复杂度的证明结束。
以上是关于《Mathematical Analysis of Algorithms》中有关“选择第t大的数”的算法分析的主要内容,如果未能解决你的问题,请参考以下文章
B. Equations of Mathematical Magic
[Python] Statistical analysis of time series
Analysis of requirement specification of parking management system
R语言协方差分析(analysis of covariance)实战:协方差分析ANCOVA(analysis of covariance)(检查模型假设)拟合协方差分析ANCOVA模型事后分析