笔记

为简化对于桶排序的分析,我们假设nn个输入数据分布在[0,1)[0, 1)区间上。将[0,1)[0, 1)区间划分为nn个相同大小的子区间,这些子区间都称为。如果输入数据是均匀分布的,可以预见每个桶所包含的元素个数是近乎均匀的,不太可能出现很多元素都落在同一个桶中的情况。为得到输出,我们先对每个桶中的元素进行排序,然按照次序把每个桶中的元素列出来即可。
  在下面桶排序的伪代码中,输入是一个包含nn个元素的数组AA,且每个元素A[i]A[i]满足0A[i]<10 ≤ A[i] < 1。此外,还需要一个临时数组B[0..n1]B[0..n−1]来存放桶,这里的桶实际上是链表。另外,对每个桶内元素的排序采用的是插入排序算法。实际上由于每个桶都是一个链表,故采用插入排序是可行的,采用快速排序、堆排序等其他排序算法反而不可行。
  算法导论 — 8.4 桶排序
  下面给出一个例子来展示桶排序算法的过程。
  算法导论 — 8.4 桶排序
  在桶排序算法中,除了第88行以外,所有其他各行的时间代价都是Θ(n)Θ(n)。我们现在来分析桶排序算法的期望运行时间。
  用随机变量nin_i表示桶B[i]B[i]中的元素个数,于是可以得到桶排序的运行时间为
    T(n)=Θ(n)+i=0n1O(ni2)T(n)=Θ(n)+\sum\limits_{i=0}^{n-1}O(n_i^2 )
  对上式取期望,得到
    E[T(n)]=E[Θ(n)+i=0n1O(ni2)]=Θ(n)+i=0n1E[O(ni2)]E[T(n)]=E[Θ(n)+\sum\limits_{i=0}^{n-1}O(n_i^2 ) ]=Θ(n)+\sum\limits_{i=0}^{n-1}E[O(n_i^2 )]
  我们先单独分析i=0n1E[O(ni2)]\sum_{i=0}^{n-1}E[O(n_i^2 )]这一项,令T=i=0n1E[O(ni2)]T'=\sum_{i=0}^{n-1}E[O(n_i^2 )]。根据OO记号的定义,存在正常量cc,使得对于足够大的nin_i,有Ti=0n1E[cni2]=i=0n1cE[ni2]T'≤\sum_{i=0}^{n-1}E[cn_i^2 ] =\sum_{i=0}^{n-1}cE[n_i^2 ] 。于是有T=i=0n1O(E[ni2])T'=\sum_{i=0}^{n-1}O(E[n_i^2 ])。于是E[T(n)]E[T(n)]可以写为
    E[T(n)]=Θ(n)+i=0n1O(E[ni2])E[T(n)]=Θ(n)+\sum\limits_{i=0}^{n-1}O(E[n_i^2 ])
  我们现在来分析E[ni2]E[n_i^2 ]。对所有i=0,1,,n1i = 0, 1, …, n−1j=1,2,,nj = 1, 2, …, n,定义指示器随机变量XijX_{ij}
    Xij=I{A[j]B[i]}X_{ij} = I\{A[j]落入桶B[i]中\}
  于是可以得到桶ii中的元素个数ni=j=1nXijn_i=\sum\limits_{j=1}^{n}X_{ij}。于是有
  算法导论 — 8.4 桶排序
  现在分别计算这两项累加和。由于我们假定输入数据服从均匀分布,所以指示器随机变量XijX_{ij}11的概率是1/n1/n,为00的概率是11/n1−1/n。于是有
    E[Xij2]=121n+02(11n)=1nE[X_{ij}^2 ]=1^2∙\frac{1}{n}+0^2∙(1-\frac{1}{n})=\frac{1}{n}
  当kjk ≠ j时,随机变量XijX_{ij}XikX_{ik}是互相独立的,因此有
    E[XijXik]=E[Xij]E[Xik]=1n1n=1n2E[X_{ij}X_{ik}]=E[X_{ij}]E[X_{ik}]=\frac{1}{n}∙\frac{1}{n}=\frac{1}{n^2}
  利用这两个期望值可以得到
    算法导论 — 8.4 桶排序
  最终可以得到桶排序算法的期望运行时间为
    E[T(n)]=Θ(n)+i=0n1O(E[ni2])=Θ(n)+nO(21n)=Θ(n)E[T(n)]=Θ(n)+\sum\limits_{i=0}^{n-1}O(E[n_i^2 ]) =Θ(n)+n∙O(2-\frac{1}{n})=Θ(n)
  根据以上分析,如果输入数据服从均匀分布,桶排序可以在线性时间内完成。然而,根据等式E[T(n)]=Θ(n)+i=0n1O(E[ni2])E[T(n)]=Θ(n)+\sum_{i=0}^{n-1}O(E[n_i^2 ]),只要满足所有桶中元素个数n0,n1,nn1n_0, n_1, …n_{n−1}的平方和i=0n1ni2=Θ(n)\sum_{i=0}^{n-1}n_i^2 =Θ(n),桶排序就仍然可以在线性时间内完成。

练习

8.4-1 参照图8-4的方法,说明BUCKET-SORT在数组A=<0.79,0.13,0.16,0.64,0.39,0.20,0.89,0.53,0.71,0.42>A = <0.79, 0.13, 0.16, 0.64, 0.39, 0.20, 0.89, 0.53, 0.71, 0.42>上的操作过程。
  
  算法导论 — 8.4 桶排序

8.4-2 解释为什么桶排序在最坏情况下运行时间是Θ(n2)Θ(n^2)?我们应该如何修改算法,使其在保持平均情况为线性时间代价的同时,最坏情况下时间代价为Θ(nlgn)Θ(n{\rm lgn})
  
  桶排序的最坏情况发生在所有元素都集中一个桶中的时候,这时候对桶内的元素调用插入排序的时间为Θ(n2)Θ(n^2)
  要使得桶排序最坏情况下的时间代价为Θ(nlgn)Θ(n\rm{lg}n),可以将桶内元素的插入排序算法替换为具有O(nlgn)O(n{\rm lg}n)时间复杂度的排序算法。然而每个桶都是一个链表,符合O(nlgn)O(n{\rm lg}n)时间复杂度并且适合链表的排序算法只有归并排序。堆排序虽然时间复杂度也为O(nlgn)O(n{\rm lg}n),但是不能应用在链表上。

8.4-3XX是一个随机变量,用于表示在将一枚硬币抛掷两次时,正面朝上的次数。E[X2]E[X^2]是多少呢?E2[X]E^2[X]是多少呢?
  
  下表列出了XX可能的取值以及概率。
  算法导论 — 8.4 桶排序
  于是有
  算法导论 — 8.4 桶排序

8.4-4 在单位圆内给定nn个点,pi=(xi,yi)p_i = (x_i, y_i),对所有i=1,2,,ni = 1, 2, …, n,有0<xi2+yi210<x_i^2+y_i^2≤1。假设所有的点服从均匀分布,即在单位元的任一区域内找到给定点的概率与该区域的面积成正比。请设计一个在平均情况下有Θ(n)Θ(n)时间代价的算法,它能够按照点到原点之间的距离di=xi2+yi2d_i=\sqrt{x_i^2+y_i^2}对这nn个点进行排序。(提示:在BUCKET-SORT中,设计适当的桶大小,用以反映各个点在单位圆中的均匀分布情况。)
  
  可以按照面积将圆等分为nn等份。由于排序是按照点到圆心的距离来进行的,所以可以用同心圆来将圆进行nn等分,如下图所示。
  算法导论 — 8.4 桶排序
  等分的目标是使得相邻同心圆之间的区域的面积相等。单位圆的面积S=π12=πS = π∙1^2 = πnn等分之后,每个区域的面积s=π/ns = π/n。可以算得同心圆的半径分别为r1=1/n,r2=2/n,,rn=n/nr_1=\sqrt{1/n}, r_2=\sqrt{2/n}, …, r_n=\sqrt{n/n}。对于第ii个等分区域,它内部的点到圆心的距离在(ri1,ri](r_{i-1}, r_i]之中 (注意:r0=0r_0 = 0)。于是,我们对单位圆内的nn个点进行桶排序,具体做法是将到圆心距离在(ri1,ri](r_{i-1}, r_i]之内的点放入第ii个桶中。
  如果按照距离来将每个点放入相应的桶中,还需要根据距离来查找相应的区间,而并不能直接将点入桶。这是因为在划分区间时,是按面积等分,而不是按距离等分。对每个点来说,用二分查找法来查找区间所花费的时间为O(lgn)O({\rm lg}n),这样一来桶排序算法的代价为O(nlgn)O(n{\rm lg}n)。而如果利用面积作为参考,可以在Θ(1)Θ(1)时间内将一个点放入到相应的桶中。对于点(xi,yi)(x_i, y_i)来说,经过该点的同心圆的面积Ai=π(xi2+yi2)A_i=π(x_i^2+y_i^2 ),那么这个点应当放入第Ai/s=n(xi2+yi2)⌈A_i/s⌉=⌈n(x_i^2+y_i^2 )⌉个桶中 (注意,这里桶的序号从11开始,而不是从00开始)。
  以下是该算法的伪代码。
  算法导论 — 8.4 桶排序

8.4-5 定义随机变量XX的概率分布函数P(x)P(x)P(x)=Pr{Xx}P(x) = Pr\{X ≤ x\}。假设有nn个随机变量X1,X2,,XnX_1, X_2, …, X_n服从一个连续概率分布函数PP,且它可以在O(1)O(1)时间内被计算得到。设计一个算法,使其能够在平均情况下在线性时间内完成这些数的排序。
  
  根据概率分布函数P(x)P(x)将随机变量X1,X2,,XnX_1, X_2, …, X_n划分到nn个桶内。对于任意一个随机变量XiX_i,将其放入第nP(X[i])⌈nP(X[i])⌉个桶 (注意,这里桶的序号从11开始,而不是从00开始)。如果nn个随机变量X1,X2,,XnX_1, X_2, …, X_n服从概率分布函数P(x)P(x),那么执行上述划分方法之后,所有随机变量应当会均匀分布在所有桶内。以下是伪代码。
  算法导论 — 8.4 桶排序
  
  代码链接:
  https://github.com/yangtzhou2012/Introduction_to_Algorithms_3rd/tree/master/Chapter08/Section_8.4

相关文章: