笔记
为简化对于桶排序的分析,我们假设n个输入数据分布在[0,1)区间上。将[0,1)区间划分为n个相同大小的子区间,这些子区间都称为桶。如果输入数据是均匀分布的,可以预见每个桶所包含的元素个数是近乎均匀的,不太可能出现很多元素都落在同一个桶中的情况。为得到输出,我们先对每个桶中的元素进行排序,然按照次序把每个桶中的元素列出来即可。
在下面桶排序的伪代码中,输入是一个包含n个元素的数组A,且每个元素A[i]满足0≤A[i]<1。此外,还需要一个临时数组B[0..n−1]来存放桶,这里的桶实际上是链表。另外,对每个桶内元素的排序采用的是插入排序算法。实际上由于每个桶都是一个链表,故采用插入排序是可行的,采用快速排序、堆排序等其他排序算法反而不可行。

下面给出一个例子来展示桶排序算法的过程。

在桶排序算法中,除了第8行以外,所有其他各行的时间代价都是Θ(n)。我们现在来分析桶排序算法的期望运行时间。
用随机变量ni表示桶B[i]中的元素个数,于是可以得到桶排序的运行时间为
T(n)=Θ(n)+i=0∑n−1O(ni2)
对上式取期望,得到
E[T(n)]=E[Θ(n)+i=0∑n−1O(ni2)]=Θ(n)+i=0∑n−1E[O(ni2)]
我们先单独分析∑i=0n−1E[O(ni2)]这一项,令T′=∑i=0n−1E[O(ni2)]。根据O记号的定义,存在正常量c,使得对于足够大的ni,有T′≤∑i=0n−1E[cni2]=∑i=0n−1cE[ni2] 。于是有T′=∑i=0n−1O(E[ni2])。于是E[T(n)]可以写为
E[T(n)]=Θ(n)+i=0∑n−1O(E[ni2])
我们现在来分析E[ni2]。对所有i=0,1,…,n−1和j=1,2,…,n,定义指示器随机变量Xij
Xij=I{A[j]落入桶B[i]中}
于是可以得到桶i中的元素个数ni=j=1∑nXij。于是有

现在分别计算这两项累加和。由于我们假定输入数据服从均匀分布,所以指示器随机变量Xij为1的概率是1/n,为0的概率是1−1/n。于是有
E[Xij2]=12∙n1+02∙(1−n1)=n1
当k=j时,随机变量Xij和Xik是互相独立的,因此有
E[XijXik]=E[Xij]E[Xik]=n1∙n1=n21
利用这两个期望值可以得到

最终可以得到桶排序算法的期望运行时间为
E[T(n)]=Θ(n)+i=0∑n−1O(E[ni2])=Θ(n)+n∙O(2−n1)=Θ(n)
根据以上分析,如果输入数据服从均匀分布,桶排序可以在线性时间内完成。然而,根据等式E[T(n)]=Θ(n)+∑i=0n−1O(E[ni2]),只要满足所有桶中元素个数n0,n1,…nn−1的平方和∑i=0n−1ni2=Θ(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>上的操作过程。
解

8.4-2 解释为什么桶排序在最坏情况下运行时间是Θ(n2)?我们应该如何修改算法,使其在保持平均情况为线性时间代价的同时,最坏情况下时间代价为Θ(nlgn)?
解
桶排序的最坏情况发生在所有元素都集中一个桶中的时候,这时候对桶内的元素调用插入排序的时间为Θ(n2)。
要使得桶排序最坏情况下的时间代价为Θ(nlgn),可以将桶内元素的插入排序算法替换为具有O(nlgn)时间复杂度的排序算法。然而每个桶都是一个链表,符合O(nlgn)时间复杂度并且适合链表的排序算法只有归并排序。堆排序虽然时间复杂度也为O(nlgn),但是不能应用在链表上。
8.4-3 设X是一个随机变量,用于表示在将一枚硬币抛掷两次时,正面朝上的次数。E[X2]是多少呢?E2[X]是多少呢?
解
下表列出了X可能的取值以及概率。

于是有

8.4-4 在单位圆内给定n个点,pi=(xi,yi),对所有i=1,2,…,n,有0<xi2+yi2≤1。假设所有的点服从均匀分布,即在单位元的任一区域内找到给定点的概率与该区域的面积成正比。请设计一个在平均情况下有Θ(n)时间代价的算法,它能够按照点到原点之间的距离di=xi2+yi2对这n个点进行排序。(提示:在BUCKET-SORT中,设计适当的桶大小,用以反映各个点在单位圆中的均匀分布情况。)
解
可以按照面积将圆等分为n等份。由于排序是按照点到圆心的距离来进行的,所以可以用同心圆来将圆进行n等分,如下图所示。

等分的目标是使得相邻同心圆之间的区域的面积相等。单位圆的面积S=π∙12=π。n等分之后,每个区域的面积s=π/n。可以算得同心圆的半径分别为r1=1/n,r2=2/n,…,rn=n/n。对于第i个等分区域,它内部的点到圆心的距离在(ri−1,ri]之中 (注意:r0=0)。于是,我们对单位圆内的n个点进行桶排序,具体做法是将到圆心距离在(ri−1,ri]之内的点放入第i个桶中。
如果按照距离来将每个点放入相应的桶中,还需要根据距离来查找相应的区间,而并不能直接将点入桶。这是因为在划分区间时,是按面积等分,而不是按距离等分。对每个点来说,用二分查找法来查找区间所花费的时间为O(lgn),这样一来桶排序算法的代价为O(nlgn)。而如果利用面积作为参考,可以在Θ(1)时间内将一个点放入到相应的桶中。对于点(xi,yi)来说,经过该点的同心圆的面积Ai=π(xi2+yi2),那么这个点应当放入第⌈Ai/s⌉=⌈n(xi2+yi2)⌉个桶中 (注意,这里桶的序号从1开始,而不是从0开始)。
以下是该算法的伪代码。

8.4-5 定义随机变量X的概率分布函数P(x)为P(x)=Pr{X≤x}。假设有n个随机变量X1,X2,…,Xn服从一个连续概率分布函数P,且它可以在O(1)时间内被计算得到。设计一个算法,使其能够在平均情况下在线性时间内完成这些数的排序。
解
根据概率分布函数P(x)将随机变量X1,X2,…,Xn划分到n个桶内。对于任意一个随机变量Xi,将其放入第⌈nP(X[i])⌉个桶 (注意,这里桶的序号从1开始,而不是从0开始)。如果n个随机变量X1,X2,…,Xn服从概率分布函数P(x),那么执行上述划分方法之后,所有随机变量应当会均匀分布在所有桶内。以下是伪代码。

代码链接:
https://github.com/yangtzhou2012/Introduction_to_Algorithms_3rd/tree/master/Chapter08/Section_8.4