第 7 章 快速排序
2017-06-21 10:01
197 查看
对于包含n个数的输入数组来说,快速排序是一种最坏情况时间复杂度为θ(n2)的排序算法。虽然最快情况时间复杂度很差,但是快速排序通常是实际排序应用中最好的选择,因为它的平均性能非常好:它的期望时间复杂度为θ(nlgn),而且θ(nlgn)中隐含的常数因子非常小。另外它还能够进行原址排序,甚至在虚存环境中也能很好地工作。
分解:数组A[p..r]被划分为两个子数组A[p..q-1]和A[q+1..r],使得A[p..q-1]中的每个元素都小于等于A[q],而A[q]也小于等于A[q+1..r]中的每个元素。其中计算下标Q也是划分过程的一部分。
解决:通过递归调用快速排序,对子数组A[p..q-1]和A[q+1..r]进行排序。
合并:因为子数组都是原址排序的,所以不需要合并操作:数组A[p..r]已经有序。
QUICKSORT
为了排序一个数组A的全部元素,初始调用是QUICKSORT(A, 1, A.length)。
数组的划分
算法的关键部分是PARTITION过程,它实现了对子数组A[p..r]的原址重拍。
PARITION(A, p, r)
最坏情况划分
当划分产生的两个子问题分别包含了n-1个元素和0个元素,快速排序的最坏情况发生了。如果算法的每一层递归上,划分都是最大程度不平衡的,那么算法时间复杂度为θ(n2).
最好情况划分
在可能的最平衡的划分中,PARTITION得到的两个子问题的规模都不大于n/2。算法时间复杂度为θ(nlgn).
平衡的划分
快速排序的平均运行时间跟接近于其最好情况,而非最坏情况。事实上,任何一种常数比例的划分都会产生深度为θ(lgn)的递归树,其中每一层的时间代价都是O(n)。因此,只要划分是常数比例的,算法的运行时间总是O(nlgn)。
对于平均情况的直观观察
当好和差的划分交替出现时,快速排序的时间复杂度与全是好的时一样,仍然是O(nlgn)。区别只是O符号中隐含的常数因子要略大一些。
我们采用随机抽样的随机化技术,从子数组A[p..r]中随机选择一个元素作为主元。首先将A[r]与A[p..r]中随机选出的一个元素交换。通过对序列p,…,r
的随机抽样,可以保证主元元素x= A[r]是等概率出现的。
RANDOMIZED-PARTITION(A, p, r)
新的快速排序:
RANDOMISED-QUICKSORT(A, p, r)
7.4 快速排序的描述
快速排序也使用了分治思想。下面对一个典型的子数组A[p..r]进行快速排序的三步分治过程:分解:数组A[p..r]被划分为两个子数组A[p..q-1]和A[q+1..r],使得A[p..q-1]中的每个元素都小于等于A[q],而A[q]也小于等于A[q+1..r]中的每个元素。其中计算下标Q也是划分过程的一部分。
解决:通过递归调用快速排序,对子数组A[p..q-1]和A[q+1..r]进行排序。
合并:因为子数组都是原址排序的,所以不需要合并操作:数组A[p..r]已经有序。
QUICKSORT
if p < r q = PARTITION(A, p, r) QUICKSORT(A, p, q-1) QUICKSORT(A, q+1, r)
为了排序一个数组A的全部元素,初始调用是QUICKSORT(A, 1, A.length)。
数组的划分
算法的关键部分是PARTITION过程,它实现了对子数组A[p..r]的原址重拍。
PARITION(A, p, r)
x = A[r] i = p-1 for j = p to r-1 if A[j} <= x i = i + 1 exchangeA[i] with A[j] exchangeA[i+1] with A[r] return i+1
7.2 快速排序的性能
快速排序的运行时间依赖于划分是否平衡,而平衡与否又依赖于划分的元素。如果划分是平衡的,那么算法性能与归并排序一样。如果划分是不平衡的,那么快速排序的性能就接近于插入排序了。最坏情况划分
当划分产生的两个子问题分别包含了n-1个元素和0个元素,快速排序的最坏情况发生了。如果算法的每一层递归上,划分都是最大程度不平衡的,那么算法时间复杂度为θ(n2).
最好情况划分
在可能的最平衡的划分中,PARTITION得到的两个子问题的规模都不大于n/2。算法时间复杂度为θ(nlgn).
平衡的划分
快速排序的平均运行时间跟接近于其最好情况,而非最坏情况。事实上,任何一种常数比例的划分都会产生深度为θ(lgn)的递归树,其中每一层的时间代价都是O(n)。因此,只要划分是常数比例的,算法的运行时间总是O(nlgn)。
对于平均情况的直观观察
当好和差的划分交替出现时,快速排序的时间复杂度与全是好的时一样,仍然是O(nlgn)。区别只是O符号中隐含的常数因子要略大一些。
7.3 快速排序的随机化版本
有时我们可以通过在算法中引入随机性,从而使得算法对于所有的输入都能获得较好的期望性能。很多人都选择随机化版本的快速排序作为大数据输入情况下的排序算法。我们采用随机抽样的随机化技术,从子数组A[p..r]中随机选择一个元素作为主元。首先将A[r]与A[p..r]中随机选出的一个元素交换。通过对序列p,…,r
的随机抽样,可以保证主元元素x= A[r]是等概率出现的。
RANDOMIZED-PARTITION(A, p, r)
i = RANDOM(p,r) exchange A[r] with A[i] return PARTITION(A, p, r)
新的快速排序:
RANDOMISED-QUICKSORT(A, p, r)
if p < r q = RANDOMIZED-PARTITION(A, p, r) RANDOMISED-QUICKSORT(A, p, q-1) RANDOMISED-QUICKSORT(A, q+1, r)
7.4 快速排序分析
7.4.1 最坏情况分析
θ(n2)7.4.2 期望运行时间
O(nlgn)相关文章推荐
- 数组排序-快速排序
- PHP排序算法系列:快速排序
- 快速排序详解以及java实现
- 快速排序、堆排序、归并排序比较
- 快速排序(C语言)
- 第十六周项目1-(4)验证算法快速排序
- 排序算法(2)冒泡排序,快速排序,归并排序和基数排序MSD,LSD
- 2018年第九届蓝桥杯【C++省赛B组】【第五题:快速排序】
- 快速排序 php
- 快速排序 常考排序算法
- 快速排序 qsort
- 快速排序--c++实现
- 白话经典算法系列之六 快速排序 快速搞定
- P1177 【模板】快速排序
- 快速排序改进
- 快速学习stl(next_premutation)全排列;nyoj会排序的小明
- 排序算法--快速排序
- [java] 快速排序
- python实现快速排序
- 蓝桥杯_算法提高_快乐的司机(快速排序、贪心算法)