對於包含n個數的輸入數組來說,快速排序是一種最壞情況時間複雜度爲
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個元素,快速排序的最壞情況發生了。如果算法的每一層遞歸上,劃分都是最大程度不平衡的,那麼算法時間複雜度爲
最好情況劃分
在可能的最平衡的劃分中,PARTITION得到的兩個子問題的規模都不大於n/2。算法時間複雜度爲
平衡的劃分
快速排序的平均運行時間跟接近於其最好情況,而非最壞情況。事實上,任何一種常數比例的劃分都會產生深度爲θ(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)