快速排序的工作原理
1,從數組中選擇一個元素,這個元素被稱為基准值(pivot)。
2,接下來,找出比基准值小的元素以及比基准值大的元素。這被稱為分區(partitioning)。
現在有:
一個由所有小於基准值的數字組成的子數組;
基准值;
一個由所有大於基准值的數組組成的子數組。
3, 對這兩個子數組進行快速排序。
4,兩個子數組里面的元素
O(n log n)
def quick_sort(list): if len(list) < 2: # 基准條件,遞歸的終止條件 return list else: pivot = list[0] # 設立基准值 less = [i for i in list[1:] if i <= pivot] #小於等於基准值的放到一個列表 greater = [j for j in list[1:] if j>= pivot] #大於等於基准值的放到一個列表 return quick_sort(less) + [pivot] + quick_sort(greater) # 返回的一個個小的列表相加 var = quick_sort([8,2,5,3,1]) print(var) # [1, 2, 3, 5, 8]
快排涉及到D&C (分而治之),遞歸調用棧原理。
快速排序的性能高度依賴於你選擇的基准值。假設你總是將第一個元素用作基准值,且要處
理的數組是有序的。由於快速排序算法不檢查輸入數組是否有序,因此它依然嘗試對其進行排序。
注意,數組並沒有被分成兩半,相反,其中一個子數組始終為空,這導致調用棧非常長。現
在假設你總是將中間的元素用作基准值,在這種情況下,調用棧如下。
調用棧短得多!因為你每次都將數組分成兩半,所以不需要那么多遞歸調用。你很快就到達
了基線條件,因此調用棧短得多。
第一個示例展示的是最糟情況,而第二個示例展示的是最佳情況。在最糟情況下,棧長為
O(n),而在最佳情況下,棧長為O(log n)。
現在來看看棧的第一層。你將一個元素用作基准值,並將其他的元素划分到兩個子數組中。
這涉及數組中的全部8個元素,因此該操作的時間為O(n)。在調用棧的第一層,涉及全部8個元素,
但實際上,在調用棧的每層都涉及O(n)個元素。
即便以不同的方式划分數組,每次也將涉及O(n)個元素。
在這個示例中,層數為O(log n)(用技術術語說,調用棧的高度為O(log n)),而每層需要的
時間為O(n)。因此整個算法需要的時間為O(n) * O(log n) = O(n log n)。這就是最佳情況。
在最糟情況下,有O(n)層,因此該算法的運行時間為O(n) * O(n) = O(n2)。
知道嗎?這里要告訴你的是,最佳情況也是平均情況。只要你每次都隨機地選擇一個數組元
素作為基准值,快速排序的平均運行時間就將為O(n log n)。快速排序是最快的排序算法之一,也
是D&C典范。