快速分类–三向和双枢轴
毫無疑問,Quicksort被認為是本世紀最重要的算法之一,并且它是許多語言(包括Java中的Arrays.sort )的事實上的系統排序。
那么,quicksort有何新功能?
嗯,除了我現在(在Java 7發行了2年之久)才想到, Arrays.sort的Quicksort實現已被替換為Dual-Pivot QuickSort的變體代替了。 出于這個原因,這個線程真棒,而且喬恩·本特利和約書亞·布洛赫真的很謙虛。
接下來我要做什么?
就像其他所有人一樣,我想實現它并針對約1000萬個整數(隨機和重復)進行一些基準測試。
奇怪的是,我發現以下結果:
隨機數據:
- 快速排序基本:1222毫秒
- 快速排序3種方式:1295毫秒(嚴重!)
- 快速分類雙樞軸:1066毫秒
重復數據:
- 快速排序基礎:378毫秒
- 快速排序3種方式:15毫秒
- 快速分類雙樞軸:6毫秒
愚蠢的問題1:
恐怕在三向分區的實現中缺少一些東西。 在針對隨機輸入(1000萬個)數字的多次運行中,我可以看到單個樞軸始終表現更好(盡管對于1000萬個數字,相差不到100毫秒)。
我知道直到現在,將3-way Quicksort設置為默認Quicksort的全部目的是它不會在重復鍵上提供0(n 2)性能-當我對重復輸入運行它時,這一點非常明顯。 但是,為了處理重復的數據,三路方式會付出一點代價嗎? 還是我的實現不好?
愚蠢的問題2
我的Dual Pivot實現(下面的鏈接)不能很好地處理重復項。 它需要永遠的甜蜜(0(n 2))才能執行。 有避免這種情況的好方法嗎? 談到Arrays.sort實現,我發現在完成實際排序之前,就消除了升序和重復項。 因此,作為一個骯臟的解決方法,如果樞軸相等,則我快進lowerIndex,直到它與pivot2不同。 這是一個公平的實施嗎?
else if (pivot1==pivot2){while (pivot1==pivot2 && lowIndex<highIndex){lowIndex++;pivot1=input[lowIndex];}}而已。 那就是我所做的一切?
我總是發現算法的跟蹤很有趣,但是由于Dual Pivot quicksort中的變量數量眾多,我的眼睛在調試時發現它不知所措。 因此,我還繼續創建了啟用跟蹤的實現(針對所有3種實現),以便可以看到變量指針當前所在的位置。
這些啟用了跟蹤的類僅覆蓋指針在數組值下方的位置。 我希望您發現這些課程有用。
例如。 用于Dual Pivot迭代
整個項目(以及DSA的一些la腳實現)可在github上找到 。 僅在這里可以找到 quicksort類。
這是我對SinglePivot(Hoare),3路(Sedgewick)和新的Dual-Pivot(Yaroslavskiy)的實現
單樞軸
package basics.sorting.quick;import static basics.sorting.utils.SortUtils.exchange; import static basics.sorting.utils.SortUtils.less; import basics.shuffle.KnuthShuffle;public class QuickSortBasic {public void sort (int[] input){//KnuthShuffle.shuffle(input);sort (input, 0, input.length-1);}private void sort(int[] input, int lowIndex, int highIndex) {if (highIndex<=lowIndex){return;}int partIndex=partition (input, lowIndex, highIndex);sort (input, lowIndex, partIndex-1);sort (input, partIndex+1, highIndex);}private int partition(int[] input, int lowIndex, int highIndex) {int i=lowIndex;int pivotIndex=lowIndex;int j=highIndex+1;while (true){while (less(input[++i], input[pivotIndex])){if (i==highIndex) break;}while (less (input[pivotIndex], input[--j])){if (j==lowIndex) break;}if (i>=j) break;exchange(input, i, j);}exchange(input, pivotIndex, j);return j;}}
3路
package basics.sorting.quick;import static basics.shuffle.KnuthShuffle.shuffle; import static basics.sorting.utils.SortUtils.exchange; import static basics.sorting.utils.SortUtils.less;public class QuickSort3Way {public void sort (int[] input){//input=shuffle(input);sort (input, 0, input.length-1);}public void sort(int[] input, int lowIndex, int highIndex) {if (highIndex<=lowIndex) return;int lt=lowIndex;int gt=highIndex;int i=lowIndex+1;int pivotIndex=lowIndex;int pivotValue=input[pivotIndex];while (i<=gt){if (less(input[i],pivotValue)){exchange(input, i++, lt++);}else if (less (pivotValue, input[i])){exchange(input, i, gt--);}else{i++;}}sort (input, lowIndex, lt-1);sort (input, gt+1, highIndex);}}
雙樞軸
package basics.sorting.quick;import static basics.shuffle.KnuthShuffle.shuffle; import static basics.sorting.utils.SortUtils.exchange; import static basics.sorting.utils.SortUtils.less;public class QuickSortDualPivot {public void sort (int[] input){//input=shuffle(input);sort (input, 0, input.length-1);}private void sort(int[] input, int lowIndex, int highIndex) {if (highIndex<=lowIndex) return;int pivot1=input[lowIndex];int pivot2=input[highIndex];if (pivot1>pivot2){exchange(input, lowIndex, highIndex);pivot1=input[lowIndex];pivot2=input[highIndex];//sort(input, lowIndex, highIndex);}else if (pivot1==pivot2){while (pivot1==pivot2 && lowIndex<highIndex){lowIndex++;pivot1=input[lowIndex];}}int i=lowIndex+1;int lt=lowIndex+1;int gt=highIndex-1;while (i<=gt){if (less(input[i], pivot1)){exchange(input, i++, lt++);}else if (less(pivot2, input[i])){exchange(input, i, gt--);}else{i++;}}exchange(input, lowIndex, --lt);exchange(input, highIndex, ++gt);sort(input, lowIndex, lt-1);sort (input, lt+1, gt-1);sort(input, gt+1, highIndex);}} 參考:快速 分揀–來自我們JCG合作伙伴 Arun Manivannan的3向和雙向樞軸 ,位于Rerun.me博客上。
翻譯自: https://www.javacodegeeks.com/2013/06/quicksorting-3-way-and-dual-pivot.html
總結
以上是生活随笔為你收集整理的快速分类–三向和双枢轴的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: (switch安卓)
- 下一篇: (linux %date)