1. 原理介紹
快速排序是一種排序算法,速度比選擇排序快得多,其主要基於“分而治之”的思想對集合進行排序,本文將對該算法進行分析。
2. 分而治之(D&C)的思想
D&C主要指利用遞歸的方式來不斷的縮小需要處理問題的規模,最終使問題容易解決。使用D&C解決問題的過程包括兩個步驟。
(1) 找出遞歸的終止條件,這種條件必須儘可能簡單(稱爲基線
條件)。
(2) 不斷將問題分解(或者說縮小規模),直到符合遞歸的終止條件(稱爲歸納條件)。
爲了便於理解,舉個例子。
假設有一個數組A=[2,4,6], 想要統計A所有元素的和,可以使用兩種方式
- 遍歷A,並將結果一個一個的加起來
- 使用D&C思想,通過不斷縮小集合的規模,最終把每次遞歸的結果加起來,流程如下
代碼如下:
// 使用dc的思想統計一個數組元素的和
func Sum(ints [] int) int {
if len(ints)==1{
//當集合只有一個元素時,返回結果
return ints[0]
}
subArr := ints[1:]
//每次遞歸的時候,傳個Sum的集合數量都比上一次少一個元素
return ints[0]+Sum(subArr)
}
3. 快速排序的原理
快速排序的流程大概分爲兩步:
-
確定遞歸的終止條件:對於排序操作而言,如果數組爲空或只包含一個元素,則只需原樣返回數組且不用排序。因此數組爲空或只包含一個元素可以作爲循環結束的條件
-
如果沒有滿足遞歸終止條件,需要將數組分解,並做以下操作,直到滿足遞歸終止條件。
2.1. 從數組中選擇一個元素,這個元素被稱爲基準值
2.2. 將數組分成兩個子數組:小於基準值的元素和大於基準值的元素
2.3. 對步驟2產生的兩個子數組再執行快速排序操作
假設要對[2,1,3,5,4]進行排序,選擇了3爲基準值,則流程大概如下:
對於快速排序,在基線條件中,我證明這種算法對空數組或包含一個
元素的數組管用。在歸納條件中,如果快速排序對包含一個元素的數組管用,對包含兩個元素的數組也將管用;如果它對包含兩個元素的數組管用,對包含三個元素的數組也將管用,以此類推。因此,可以說明快速排序對任何長度的數組都管用。
4. 運行時間分析
快速排序的平均情況運行的時間複雜度爲O(n log n),但在最糟糕的情況下其複雜度將爲O(n^2),下面對兩種情況進行分析
4.1 最糟糕情況
下面來看看到底啥時候纔會出現最糟糕的情況,考慮如下的排序:
快速排序的性能高度依賴於你選擇的基準值。假設你總是將第一個元素用作基準值,且要處
理的數組是有序的。由於快速排序算法不檢查輸入數組是否有序,因此它依然嘗試對其進行排序,需要進行N層操作,每層需要比較N個數。所以算法複雜度爲O(n^2)
4.2 最佳情況
考慮如下排序:
該圖也是對有序數組進行排序,但每次都選擇中間的元素作爲基準值,此時遞歸的次數變成了3次(logN),每次也是需要比較N個元素,所以算法複雜度爲O(n log n)
5. 代碼實現
爲了簡單演示,代碼都始終選用第一個元素作爲基準值
Python版本:
def quicksort(array):
if len(array) < 2:
return array
else:
pivot = array[0]
less = [i for i in array[1:] if i <= pivot]
greater = [i for i in array[1:] if i > pivot]
return quicksort(less) + [pivot] + quicksort(greater)
print quicksort([3,5,6,2,6,2])
總結
- D&C將問題逐步分解。使用D&C處理列表時,基線條件很可能是空數組或只包含一個元
素的數組。 - 快速排序的平均運行時間爲O(n log n)。
- 當數組有序,始終選擇第一元素作爲基準值時,快速排序將出現最糟情況
- 當數組有序,始終選擇中間元素作爲基準值時,快速排序將出現最佳情況