快速排序採用分治的思想對資料進行排序
選擇乙個基準值
將比基準值小的放在基準值的左邊,其餘的(大於或者等於)放在右邊
然後再對左邊和右邊繼續進行劃分,直到劃分的區間長度為1
快速排序劃分區間的時候為o(logn),每次都需要時間複雜度為o(n)進行排序
所以快排的時間複雜度是o(nlogn),這是將對於基準值可以大概可以將區間進行等分的情況下
如果資料已經有序,每次分治的時候就有可能導致一邊沒有乙個資料,另一邊卻都是資料,這樣就和氣泡排序一樣了,時間複雜度是o(n^2)
綜上所述:
最好的時間複雜度:o(nlogn)
最壞的時間複雜度:o(n^2)
快速排序適合用於資料無序的情況,當資料有序的時候時間複雜度極有可能是o(n^2),沒有體現出快排的優點
當劃分成小區間的時候,採用插入排序,不再使用快速排序
對於遞迴實現的快排可以改為非遞迴,使用棧來進行實現
每次選擇基準值的時候,不再直接選擇第乙個或者最後乙個元素。
可以採用三數取中法,或者隨機選擇乙個基準值
對於快排的partion函式有著三種實現方法:
左右指標的方法
挖坑法前後指標法
此處採用前後指標的方法,進行實現
//前後指標法
int partion(int array, int left, int right)
cur++;
}std::swap(array[++prev], array[right]);
return prev;}
void quicksort(int array, int left, int right)
if (left < right)
}
其他實現方法以及優化**:
對於快排,如果資料元素過多並且元素的大小都是非常接近的,這時候左右分治的時候,就會導致一邊全是資料,另一邊沒有資料,這樣就會導致效率降低,時間複雜度變為o(n^2)
舉例:用模板測試歸併排序和快速排序的時間,設定乙個1000000的陣列,陣列元素在0-10之間隨機取值,那麼用歸併需要花費0.290727s而快排需要花費171.151s,對,你沒有看錯。當快速排序最優的時候是o(nlgn),而此時顯然退化到了o(n^2)的級別。這是為什麼?
對於上面我寫的快排,將小於等於基準值的資料全都放到了左邊,大於的放到右邊了,那麼這樣就會出現問題。不管是當條件大於等於還是小於等於,當陣列中重複元素非常多的時候,等於基準值的元素太多,那麼陣列就會分成極度不平衡的兩個部分,因為等於基準值的一部分總是集中在陣列的一邊。
此時,使用二路快排就可以進行優化,阻止效率的降低。
二路快排解決的問題:
不會讓等於基準值的元素全部都集中在陣列的一邊。
我們將小於基準值的元素全部放在陣列的左邊,大於基準值的元素放在陣列的右邊
對於左邊有著乙個索引left,右邊有著乙個索引right
當left小於基準值的時候一直向後++,直到碰到某個大於等於基準值的left;right大於基準值的時候一直向前--,直到碰到某個小於等於基準值的right
此時交換left和right處的資料元素,然後left++,right--
繼續執行第2不,直到left==right停止
此時,交換基準值和left位置的元素,返回基準值即可
這種思想,即使是重複的資料元素很多,也可以將其幾乎平分開來,不會造成一邊資料量極大,另一邊沒有資料
當陣列中重複的元素過多的時候,就不能在用快排,使用二路快排即可
實現的時候,只需要改變,partion函式即可
int partion_two(int array, int left, int right)
while (l <= r && array[r] > array[right])
if (l > r)
std::swap(array[r], array[l]);
}std::swap(array[l], array[right]);
return r;
}
注意:左邊找不小於的,右邊找不大於的,然後進行判斷交換
將陣列分成三部分,小於基準值,大於基準值以及等於基準值的
記錄下三個下標:
lt:小於基準值的最後乙個下標
gt:大於基準值的第乙個下標
index:正在遍歷的下標
index小於基準值:交換index和lt+1,lt++
index大於基準值:交換index和gt-1,gt--
index等於基準值:index++
結束條件:index==gt
最後一步交換基準值:
swap(arr[lt], arr[right])
繼續進行的區間:
[left,lt-1]
[gt, right]
void quicksort_three(int array, int left, int right)
if (right <= left)
int lt = left - 1;
int gt = right;
int index = left;
int key = array[right];
while (index < gt)
else if (array[index] > key)
else
}std::swap(array[index], array[right]);
quicksort_three(array, left, lt );
quicksort_three(array, gt, right);
}
快速排序之三路快排
當大量出現重複值時,我們使用三路快排,如下 arr 表示排序陣列 l 表示陣列左邊界 r 表示陣列右邊界 public static void quicksortinternal3 int arr,int l,int r else if arr i v else 交換l與lt元素,可以確定基準值的位...
三路快排板子
還是覺得別人的快排寫得太醜了 雙路快排 void qsort2 int l,int r 隨機取值 int index rand r l 1 l swap nums l nums index int key nums l int i l,j r while i j nums i nums j whil...
Java快速排序以及其優化(雙路快排 三路快排)
快速排序是屬於交換排序的基本思想。選擇乙個基準值val,把比val小的放在前面,比val大的放在後面,最後把val放在兩個區域中間,val就到了最終的位置。很明顯快排是乙個原地排序,也是乙個不穩定排序。空間複雜度 1.可以是為新陣列開闢額外空間o n 2.當然也可以在原陣列內交換得來o 1 時間複雜...