快速排序(quickSort)
阿新 • • 發佈:2017-08-19
str nlogn swap void spa 元素 完成 partition 一個
快速排序是最經典和常用的排序算法了,已經有不計其數的博客0 0
首先介紹下快速排序的原理。快速排序的基礎是基於這樣的事實:在一個序列中,如果一個節點前面的所有元素都不大於它,後面的所有元素都不小於它,那麽當整個序列達到有序狀態時,這個節點的位置保持不變。符合這樣條件的節點,稱為軸點(pivot)。
於是可以想到,如果能找到這個軸點,那麽該點就完成了排序,可以繼續在前、後的兩個子序列繼續尋找軸點。然而,軸點很可能是不存在的,因此,需要我們來構造軸點,即選定一個點,通過調整該點的前後子序列,使之符合軸點的要求。
軸點構造算法如下,總體思想就是,取出一個點作為軸點,然後從起始和末尾元素進行比較,發現不符合的元素,即把它調整到另一側。當兩者相匯時,即均已調整完成,算法即可結束。
1 int partition(int* A, int lo, int hi) 2 { 3 swap(A[lo], A[lo + rand() % (hi - lo + 1)]);//隨機選取一個元素 4 int pivot = A[lo];//作為軸點 5 while (lo < hi) 6 { 7 while (lo < hi) 8 { 9 if (pivot < A[hi]) 10 hi--; 11 else 12 {13 A[lo++] = A[hi]; break;//遇到相同元素直接轉到另一側 14 } 15 } 16 while (lo < hi) 17 { 18 if (pivot > A[lo]) 19 lo++; 20 else 21 { 22 A[hi--] = A[lo]; break;//同上 23 } 24 }25 } 26 A[lo] = pivot;//位置已經調整好,把保存的軸點放回 27 return lo; 28 }
需要註意的一點是,如果判斷條件為<=時,如果有很多相同元素,會導致前後子序列劃分非常不均衡,遞歸深度為O(n),總體運行時間高達O(n^2)。因此盡可能讓前後序列長度相差較小,碰到相同元素即跳過並從另一邊繼續。
有了軸點構造,快速排序算法就非常容易了。每次軸點構造確定了mi的位置,只需要在前後子序列遞歸進行這一過程即可。
1 void quickSort(int* A, int lo, int hi) 2 { 3 if (hi - lo < 2) return;//遞歸基 4 int mi = partition(A, lo, hi - 1); 5 quickSort(A, lo, mi);//遞歸進行 6 quickSort(A, mi + 1, hi); 7 }
對於快速排序的復雜度,在最壞情況下可能會高達O(n^2),不過在平均效率上,為O(nlogn)。因此,快速排序並不一定真的非常快速0 0
另外,軸點構造算法在中位數和選取問題中也有應用,後面會寫一篇top-K問題,會詳細介紹軸點構造的應用。
快速排序(quickSort)