資料結構 快速排序,二路快排,三路快排

2021-09-16 22:59:10 字數 3305 閱讀 1977

快速排序採用分治的思想對資料進行排序

選擇乙個基準值

將比基準值小的放在基準值的左邊,其餘的(大於或者等於)放在右邊

然後再對左邊和右邊繼續進行劃分,直到劃分的區間長度為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 時間複雜...