以前也無數次的看過快速排序,也無數次死記硬背過快排,今天再次看到快排的時候才恍然大悟,原來可以這么簡單的實現快排。廢話不說了,直接開車吧。
快排是一種采用分而治之(divide and conquer,D&C)思想的算法,D&C也是一種著名的遞歸式解決問題的方法。既然是遞歸算法,那么解決問題的過程通常就包括了兩個步驟。
- 找到盡可能簡單的基線條件
- 不斷將問題分解(或者縮小規模),直到符合基線條件
那么對于排序算法來說,最簡單的數組時什么樣呢?
最簡單的數組
因此,基線條件為數組為空或只包含一個元素,這樣的情況下,只需要原樣返回數組——根本不用排序。
def quicksort(array):
if len(array)<2:
return array
對包含兩個元素的數組排序只需要比較大小交換順序就可以了
對兩個元素排序
對包含三個元素的數組呢?不要忘了咱使用的可是D&C,根據遞歸策略,對數組進行分解,直到滿足基線條件。接下來是快排的工作原理了:
首先從數組中選擇一個元素,一般被叫做基準值(pivot),一般我們會將數組的第一個元素作為基準值(其實不一定合適),接下來找到比基準值小和大的元素,即分區(partitioning)。如下圖所示:
含有3個元素的數組
分區(partitioning)
現在我們有:
- 一個由小于基準值的數字組成的子數組
- 基準值
- 一個由大于基準值數組組成的子數組
以上只是進行了分區,得到的兩個子數組是無序的,如果是有序的,那么合并后就是一個有序的數組了。那么如何對子數組進行排序呢?快排知道如何將他們排序,因此只需要進行快排,然后合并結果就可以了。
quicksort([15,10]) + [33] + quicksort([])
> [10,15,30]
因此最后實現快排的代碼:
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([9, 4, 6, 10, 30, 26, 4]))
> [4, 4, 6, 9, 10, 26, 30]
說好的3行代碼呢!借助于python的簡潔,上面的代碼可以簡化為:
def quicksort(array):
if len(array) < 2: return array
return quicksort([lt for lt in array[1:] if lt < array[0]]) + [array[0]] + quicksort([ge for ge in array[1:] if ge >= array[0]])