New portion of improvements for Dual-Pivot Quicksort

Vladimir Iaroslavski vladimir.iaroslavski at googlemail.com
Mon Apr 26 21:50:08 UTC 2010


Hello, everyone!

I've investigated the implementation of the Dual-Pivot Quicksort
which is used for sorting primitives and here is my result:

http://cr.openjdk.java.net/~alanb/6947216/webrev.00

New implementation of Dual-Pivot Quicksort is faster
than previous one of 12% for client VM and few percents for
server VM. Tests on Bentley's test suite (Win XP, JDK 7,
build 1.7.0-ea-b84, n = 1000000) show geometry mean 0.88
for client VM and 0.98-1.00 for server VM.

In compare with sorting from JDK 6 by Jon L. Bentley and
M. Douglas McIlroy's (with one pivot) the ratio is 0.61 / 0.50
(client / server).

See the execution time for sorting array of 2`000`000 int elements
50 times, client / server VM, in milliseconds:

random
 new: 16723 18776
jdk7: 17571 18975
jdk6: 22241 26524

ascendant
 new:  3541  4702
jdk7:  4486  4669
jdk6:  8667  7978

descendant
 new:  3854  4907
jdk7:  4942  5034
jdk6:  8787  8243

equal
 new:   234   281
jdk7:   291   230
jdk6:   602  1018

organ pipes
 new:  7673  8613
jdk7:  8167  8993
jdk6: 11902 14044

stagger 1
 new:  7648  8591
jdk7:  8161  8979
jdk6: 11908 13810

stagger 2
 new:  8349  9299
jdk7: 10968 11916
jdk6: 12194 14734

stagger 4
 new:  8475  9622
jdk7:  9221  9682
jdk6: 10523 12006

stagger 8
 new:  9321 10689
jdk7: 11125 12387
jdk6: 13829 16214

period 1..2
 new:   758   751
jdk7:   870   754
jdk6:  1038  1227

period 1..4
 new:  1004   963
jdk7:  1365  1209
jdk6:  1511  1847

period 1..8
 new:  1588  1573
jdk7:  1599  1790
jdk6:  2602  3045

random 1..2
 new:  1327  1125
jdk7:  1362  1496
jdk6:  1531  2182

random 1..4
 new:  1830  2118
jdk7:  1851  2236
jdk6:  2292  3025

where stagger(m) is array like a[i] = i * (m + 1) % length.

The summary of changes is:

1. For sorting small arrays is used insertion sort with sentinel
instead of traditional, which has the structure:

for (int i = left + 1; i <= right; i++) {
    for (j = i; j > left && a[j-1] > a[j]; j--) {
        swap(a[i], a[j-1]);
    }
}

Note that range check j > left is performed on each iteration,
but really helps very rare. To avoid this expensive range check,
it was suggested to set minimum value (negative infinity) on the
first position. This type of suggestion is used in new version:

if left bound > 0, we can put sentinel on a[left - 1], do insertion
sort without expensive check range, and then restore a[left - 1]
value. If left == 0, traditional insertion sort is used. Please,
look at the webrev for details.

2. In previous implementation 5 evenly spaced elements

sixth = length / 6;
a[sixth], a[2 * sixth], a[3 * sixth], a[4 * sixth], a[5 * sixth]

were used as candidates of pivots elements. This case is very
sensitive for period inputs, especially by 6. The new suggestion
is to take 5 center evenly spaced elements like this:

int seventh = length / 7;
int midpoint = (left + right) >>> 1;

a[midpoint - 2 * seventh], a[midpoint -     seventh], a[midpoint],
a[midpoint +     seventh], a[midpoint + 2 * seventh]

and moreover, the seventh is calculated inexpensively:
seventh = (length >>> 3) + (length >>> 6) + 1;

This schema works the same on random, ascendant, descendant, equal
inputs, but much better for period / stagger.

3. The whole structure

<choose pivots>

if (pivotsDiffer) {
    <do partitioning for two pivots>
}
else {
    <do partitioning for one pivot>
}

<sort left and right parts>

if (!pivotsDiffer) {
    return;
}
<swap internal pivot values to ends>

<sort center part>

was modified to:
----------------

<choose pivots>

if (pivot1 < pivot2) {
    <do partitioning for two pivots>
    <swap pivots into their final positions>
    <sort left and right parts>
    <swap internal pivot values to ends>
    <sort center part>
}
else {
    <do partitioning for one pivot>
    <sort left and right parts>
}

4. Partitioning for both cases have not been changed at all.

5. Minor javadoc and format changes.

Please, review new implementation,
any comments / suggestions are welcome!

Thank you,
Vladimir



More information about the core-libs-dev mailing list