快速排序虽然最坏情况下时间复杂度在O(n^2),但它是实际排序应用中最好的选择,它的平均性能时间复杂度在O(nlgn),其隐含常熟因子非常小。其次,它能进行原址排序,在虚存中也能很好工作。
快速排序描述
思想:分治(在分治策略中,递归求解一个问题)
-
分解:将问题划分成多个子问题,形式与原问题相同,只是规模更小
-
解决:递归求解子问题。子问题规模足够小则停止递归,直接求解。
-
合并:将子问题的解组合成原问题的解
分治在快排中的应用
分解:
-
数组A[p...r]被划分成两个(可能为空)子数组A[p...q-1]和A[q+1...r],
-
使得A[p..q-1] <= A[q] , A[q] <= A[q+1...r]中的元素
解决:递归调用快排,对子数组A[p...q-1]和A[q+1...r]进行排序
合并:子数组都是原址排序,不需要合并操作,数组A[p...r]已经有序
快排实现
QUICKSORT(A, p, r){
if p < r
q = PARTITION(A, p, r)
QUICKSORT(A, p, q-1)
QUICKSORT(A, q+1, r)
}//排序整个数组,初始调用QUICKSORT(A, 1, A.length)
数组的划分,PARTITION的实现
PARTITION(A, p, r){
x = A[r]
i = p - 1
for j = p to r - 1
if A[j] <= x
i = i + 1
exchange A[i] with A[j]
exchange A[i+1] with A[r]
return i + 1
}//x = A[i]是主元,围绕x划分子数组A[p...r]
上述程序执行循环过程中,把数组A划分成了4个区域:
这4个区域,满足:
-
若p<=k<=i, 则A[k] <= x
-
若i+1 <= k <= j-1, 则A[k] > x
-
若k = r, 则A[k] = x
-
j~r-1,无限制关系
初始化:循环第一轮迭代开始前,i = p - 1,j = p
保持:
(1)A[j] > x
此时,根据上述实现循环体唯一操作是j加1。
(2)A[j] <= x
i值增加1,交换A[i] 和A[j],j值增加1,所以交换后A[i] <= x, 且A[j - 1] > x
终止:
j == r条件成立,则把数组分成了三个集合:<= x, == x, > x。通过算法最后两行exchange A[i+1] with A[r]把A[r]主元和A[i+1]交换,返回主元新下标。
通过以上分析,满足循环不变量的特性,证明了快排算法的正确性。同时也得到PARTITION过程的时间复杂度是O(n),(n=r-p+1).
对一次PARTITION过程举例