算法导论 — 7.2 快速排序的性能

笔记

本节只给出快速排序运行时间的简单分析。快速排序的运行时间取决于PARTITION划分是否平衡,而划分的平衡与否又取决于用于划分的主元的选择。
  1. 最坏情况时间复杂度
  对于一个含 n n n个元素的数组,PARTITION划分的最坏情况为:划分产生的两个子数组的大小分别为 n − 1 n-1 n1 0 0 0时。假设快速排序每一次递归调用PARTITION都产生了最坏情况划分,那么算法的运行时间 T ( n ) T(n) T(n)满足以下递归式。
   T ( n ) = T ( n − 1 ) + T ( 0 ) + Θ ( n ) = T ( n − 1 ) + Θ ( n ) T(n) = T(n-1) + T(0) + Θ(n) = T(n-1) + Θ(n) T(n)=T(n1)+T(0)+Θ(n)=T(n1)+Θ(n)
  求解这个递归式得到 T ( n ) = Θ ( n 2 ) T(n) = Θ(n^2) T(n)=Θ(n2)。也就是说,如果快速排序的每一次递归调用都产生了最坏情况划分,那么算法的时间复杂度为 Θ ( n 2 ) Θ(n^2) Θ(n2)
  快速排序最坏情况的一个例子是,输入数组已经完全有序,此时快速排序的时间复杂度为 Θ ( n 2 ) Θ(n^2) Θ(n2)。而同样的情况下,如果采用插入排序,时间复杂度为 Θ ( n ) Θ(n) Θ(n)。因此,在数组已经有序的时候,插入排序要优于快速排序。
  2. 最好情况时间复杂度
  快速排序的最好情况出现在:每一次PARTITION都得到一个完全平衡的划分,即对于一个含 n n n个元素的数组,PARTITION产生的两个子数组的大小分别为 ⌊ ( n − 1 ) / 2 ⌋ ⌊(n-1)/2⌋ (n1)/2 ⌈ ( n − 1 ) / 2 ⌉ ⌈(n-1)/2⌉ (n1)/2。假设快速排序每一次递归调用都产生了最好情况划分,那么算法的运行时间 T ( n ) T(n) T(n)满足以下递归式。
   T ( n ) = 2 T ( n / 2 ) + Θ ( n ) T(n) = 2T(n/2) +Θ(n) T(n)=2T(n/2)+Θ(n)
  求解这个递归式得到 T ( n ) = Θ ( n l g n ) T(n) = Θ(nlgn) T(n)=Θ(nlgn),这就是快速排序最好情况的时间复杂度。
  3. 平均情况的时间复杂度
  本节给出了结论:快速排序的平均情况时间复杂度为 Θ ( n l g n ) Θ(n{\rm lg}n) Θ(nlgn)。本节对这一结论只做了简要的说明,在7.4节会给出严格的证明,我们先记下这个结论。

练习

7.2-1 利用代入法证明:正如7.2节开头提到的那样,递归式 T ( n ) = T ( n − 1 ) + Θ ( n ) T(n) = T(n-1) + Θ(n) T(n)=T(n1)+Θ(n)的解为 T ( n ) = Θ ( n 2 ) T(n) = Θ(n^2) T(n)=Θ(n2)
  
  
  
7.2-2 当数组 A A A的所有元素都具有相同的值时,QUICKSORT的时间复杂度是什么?
  
  利用练习7.1-2的结论,当所有元素都相同时,每次调用PARTITION都产生一个最坏情况划分,因此这种情况下,QUICKSORT的时间复杂度为 Θ ( n 2 ) Θ(n^2) Θ(n2)
  
  
7.2-3 证明:当数组 A A A包含的元素各不相同,并且是按降序排列的时候,QUICKSORT的时间复杂度为 Θ ( n 2 ) Θ(n^2) Θ(n2)
  
  考虑包含 n n n个元素的数组 A A A,其中元素各不相同,并且按降序排列,即 a 1 > a 2 > … > a n a_1 > a_2 > … > a_n a1>a2>>an。我们来分析每次调用PARTITION的情况。
  在这里插入图片描述
  第 1 1 1次划分,调用 P A R T I T I O N ( A , 1 , n ) {\rm PARTITION}(A, 1, n) PARTITION(A,1,n),由于被选为划分主元的 a n a_n an是最小的,所以最终 a 1 a_1 a1 a n a_n an交换,产生最坏情况划分。
  第 2 2 2次划分,调用 P A R T I T I O N ( A , 2 , n ) {\rm PARTITION}(A, 2, n) PARTITION(A,2,n),由于被选为划分主元的 a 1 a_1 a1是最大的,所以这次划分没有任何改变,也是一个最坏情况划分。
  接下来的第 3 3 3次划分,调用 P A R T I T I O N ( A , 2 , n − 1 ) {\rm PARTITION}(A, 2, n-1) PARTITION(A,2,n1),此时数组 A [ 2.. n − 1 ] A[2..n-1] A[2..n1]又是一个降序排列的数组,因此也产生一个最坏情况划分。
  如此循环往复下去,每次调用 P A R T I T I O N {\rm PARTITION} PARTITION都产生一个最坏情况划分。所以数组按降序排列的情况下,QUICKSORT的时间复杂度为 Θ ( n 2 ) Θ(n^2) Θ(n2)
  
  
7.2-4 银行一般会按照交易时间来记录某一账户的交易情况。但是,很多人却喜欢收到的银行对账单是按照支票号码的顺序来排列的。这是因为,人们通常都是按照支票号码的顺序来开出支票的,而商人也通常都是根据支票编号的顺序兑付支票。这一问题是将按交易时间排序的序列转换成按支票号排序的序列,它实质上是一个对几乎有序的输入序列进行排序的问题。请证明:在这个问题上,INSERTION-SORT的性能往往要优于QUICKSORT。
  
  根据前面的分析,对于一个几乎有序的数组,插入排序接近它的最好情况,时间复杂度接近 Θ ( n ) Θ(n) Θ(n)。而快速排序接近它的最坏情况,时间复杂度接近 Θ ( n 2 ) Θ(n^2) Θ(n2)。所以插入排序的性能要优于快速排序。
  
  
7.2-5 假设快速排序的每一层所做的划分的比例都是 1 − α : α 1-α:α 1αα,其中 0 &lt; α ≤ 1 / 2 0 &lt; α ≤ 1/2 0<α1/2且是一个常数。试证明:在相应的递归树中,叶结点的最小深度大约是 l g n / l g α {\rm lg}n/{\rm lg}α lgn/lgα,最大深度大约是 l g n / l g ( 1 − α ) {\rm lg}n/{\rm lg}(1-α) lgn/lg(1α)(无需考虑整数舍入问题)。
  
  在递归树中,最小深度的叶结点出现在每次划分比例为 α α α的分枝,即子问题规模较小的那个分枝,它的深度为 l o g α n = l g n / l g α {\rm log}_αn = {\rm lg}n/{\rm lg}α logαn=lgn/lgα
  在递归树中,最大深度的叶结点出现在每次划分比例为 1 − α 1-α 1α的分枝,即子问题规模较大的那个分枝,它的深度为 l o g 1 − α n = l g n / l g ( 1 − α ) {\rm log}_{1-α}n = {\rm lg}n/{\rm lg}(1-α) log1αn=lgn/lg(1α)
  
  
7.2-6 试证明:在一个随机输入数组上,对于任何常数 0 &lt; α ≤ 1 / 2 0 &lt; α ≤ 1/2 0<α1/2,PARTITION产生比 1 − α : α 1-α:α 1αα更平衡的划分的概率约为 1 − 2 α 1-2α 12α
  
  对数组的划分取决于被选择的划分主元。假如数组大小为 n n n。如果划分主元是数组中最大的 α n αn αn个元素中的一个,那么对数组的划分一定不会比 1 − α : α 1-α:α 1αα更平衡。如果划分主元是数组中最小的 α n αn αn个元素中的一个,那么对数组的划分也一定不会比 1 − α : α 1-α:α 1αα更平衡。对于数组中间的 n − 2 α n n-2αn n2αn个元素,如果划分主元是其中一个,那么产生的划分才会比 1 − α : α 1-α:α 1αα更平衡。
  对于一个随机输入数组,数组中的每一个元素都有相同的概率被选为划分主元。根据前面的分析,产生比 1 − α : α 1-α:α 1αα更好的划分的概率,也等于划分主元为中间的 n − 2 α n n-2αn n2αn个元素之一的概率,这个概率为 ( n − 2 α n ) / n = 1 − 2 α (n-2αn)/n = 1-2α (n2αn)/n=12α

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值