笔记
7.2节提到,快速排序的平均情况时间复杂度为
。然而实际应用中,输入数据有可能并不是完全随机排列的。比如,练习7.2-4描述的应用,需要排序的绝大多数输入数组都已经是基本有序的,在这种应用中,快速排序的效率总是十分低下。
为了避免在某些应用中,由于输入数据并不是完全随机排列的,它们可能具备或大致上具备某种规律性,从而导致快速排序总是效率低下,可以通过在算法中引入随机性,使得快速排序算法在这些应用中也能得到较好的期望性能。即每次调用PARTITION(A, p, r)时,随机选择一个元素作为划分主元,而不是固定选择
。
对于上文提到的输入数组总是基本有序的情况,随机化版本的快速排序算法也可以得到较好的平均时间复杂度。
练习
7.3-1 为什么我们分析随机化算法的期望运行时间,而不是其最坏运行时间呢?
解
对于相同的输入,随机化算法每次运行的时间都各不相同。因此即使对于相同的输入,我们也可以认为算法的运行时间是一个随机变量。而对于一个随机变量,我们通常关注它的期望值。
我们根本无法预测随机化算法在什么时候会出现最坏情况运行时间,因此分析最坏运时间意义不大。
7.3-2 在RANDOMIZED-QUICKSORT的运行过程中,在最坏情况下,随机数生成器RANDOM被调用了多少次?在最好情况下呢?以
符号的形式给出你的答案。
解
在RANDOMIZED-QUICKSORT的最坏情况下,对于一个包含
个元素的数组,划分得到的两个子数组的大小分别为
和
。其中,大小为
的子数组会进一步划分。因此,划分过程一共被调用了
次,那么随机数生成器也一共被调用了
次,即
。
在RANDOMIZED-QUICKSORT的最好情况下,每次划分都是完全平衡的划分,即划分得到的
个子数组的规模分别为
和
。于是可以得到调用划分过程的次数,也即调用随机数生成器的次数的递归式为
有经验的读者应该一眼能看出这个递归不等式的解为
。如果要严格证明,我们需要用代入法去验证这个递归不等式。应用代入法时应当假设
,其中
并且
。
我们先考察初始情况,初始情况为
和
。当
时,有
,即空的子数组是不需要进行划分的。根据我们对
的假设,有
,这个不等式显而易见是成立的 (因为我们已经假设了
)。
当
时,有
,即单个元素的子数组也是不需要进行划分的。根据我们对
的假设,有
,显然当
时,这个不等式是成立的。即只要满足不等式
,那么
对
一定成立。
下面进入数学归纳过程。假设
对
都成立。于是有
为了让
成立,我们令
,可以得到
。这说明只要满足不等式
,就可以使得
成立。
综合初始情况和归纳过程,可以得到只要满足不等式
,就可以使得
对所有
的取值都成立。比如我们可以取
并且
,此时不等式
是成立的,于是可以断言
以上只得到了
的下限。而
的上限是显而易见的,即
,因为数组一共有
个元素,每个元素至多被选为划分主元一次。综上所述,
。即在RANDOMIZED-QUICKSORT的最好情况下,随机数生成器被调用的次数也为
。
这里再多提一下,为什么初始情况要考察
和
两项?首先我们要证明的不等式
,
的取值范围是
,因此初始情况必须包含
。而递归不等式
,
的取值范围是
,因为将
代入这个不等式得到
,这显然是不成立的 (因为
等于
)。所以进入数学归纳过程必须将
排除在外,而应当从
开始归纳,故
就被列入初始情况。