提交 615ec5db 编写于 作者: A alanb

7013585: Dual-pivot quicksort improvements for highly structured (nearly...

7013585: Dual-pivot quicksort improvements for highly structured (nearly sorted) and data with small periods
Reviewed-by: mduigou, alanb
Contributed-by: vladimir.yaroslavskiy@oracle.com
上级 dcaf1073
...@@ -36,7 +36,7 @@ package java.util; ...@@ -36,7 +36,7 @@ package java.util;
* @author Jon Bentley * @author Jon Bentley
* @author Josh Bloch * @author Josh Bloch
* *
* @version 2010.10.13 m765.827.12i:5\7p * @version 2011.01.21 m765.827.12i:5\7pm
* @since 1.7 * @since 1.7
*/ */
final class DualPivotQuicksort { final class DualPivotQuicksort {
...@@ -50,6 +50,22 @@ final class DualPivotQuicksort { ...@@ -50,6 +50,22 @@ final class DualPivotQuicksort {
* Tuning parameters. * Tuning parameters.
*/ */
/**
* The maximum number of runs in merge sort.
*/
private static final int MAX_RUN_COUNT = 67;
/**
* The maximum length of run in merge sort.
*/
private static final int MAX_RUN_LENGTH = 33;
/**
* If the length of an array to be sorted is less than this
* constant, Quicksort is used in preference to merge sort.
*/
private static final int QUICKSORT_THRESHOLD = 286;
/** /**
* If the length of an array to be sorted is less than this * If the length of an array to be sorted is less than this
* constant, insertion sort is used in preference to Quicksort. * constant, insertion sort is used in preference to Quicksort.
...@@ -78,7 +94,7 @@ final class DualPivotQuicksort { ...@@ -78,7 +94,7 @@ final class DualPivotQuicksort {
* @param a the array to be sorted * @param a the array to be sorted
*/ */
public static void sort(int[] a) { public static void sort(int[] a) {
sort(a, 0, a.length - 1, true); sort(a, 0, a.length - 1);
} }
/** /**
...@@ -89,7 +105,89 @@ final class DualPivotQuicksort { ...@@ -89,7 +105,89 @@ final class DualPivotQuicksort {
* @param right the index of the last element, inclusive, to be sorted * @param right the index of the last element, inclusive, to be sorted
*/ */
public static void sort(int[] a, int left, int right) { public static void sort(int[] a, int left, int right) {
// Use Quicksort on small arrays
if (right - left < QUICKSORT_THRESHOLD) {
sort(a, left, right, true); sort(a, left, right, true);
return;
}
/*
* Index run[i] is the start of i-th run
* (ascending or descending sequence).
*/
int[] run = new int[MAX_RUN_COUNT];
int count = 0; run[0] = left;
// Check if the array is nearly sorted
for (int k = left; k < right; run[count] = k) {
if (a[k] < a[k + 1]) { // ascending
while (++k <= right && a[k - 1] <= a[k]);
} else if (a[k] > a[k + 1]) { // descending
while (++k <= right && a[k - 1] >= a[k]);
for (int lo = run[count] - 1, hi = k; ++lo < --hi; ) {
int t = a[lo]; a[lo] = a[hi]; a[hi] = t;
}
} else { // equal
for (int m = MAX_RUN_LENGTH; ++k <= right && a[k - 1] == a[k]; ) {
if (--m == 0) {
sort(a, left, right, true);
return;
}
}
}
/*
* The array is not highly structured,
* use Quicksort instead of merge sort.
*/
if (++count == MAX_RUN_COUNT) {
sort(a, left, right, true);
return;
}
}
// Check special cases
if (run[count] == right++) { // The last run contains one element
run[++count] = right;
} else if (count == 1) { // The array is already sorted
return;
}
/*
* Create temporary array, which is used for merging.
* Implementation note: variable "right" is increased by 1.
*/
int[] b; byte odd = 0;
for (int n = 1; (n <<= 1) < count; odd ^= 1);
if (odd == 0) {
b = a; a = new int[b.length];
for (int i = left - 1; ++i < right; a[i] = b[i]);
} else {
b = new int[a.length];
}
// Merging
for (int last; count > 1; count = last) {
for (int k = (last = 0) + 2; k <= count; k += 2) {
int hi = run[k], mi = run[k - 1];
for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) {
if (q >= hi || p < mi && a[p] <= a[q]) {
b[i] = a[p++];
} else {
b[i] = a[q++];
}
}
run[++last] = hi;
}
if ((count & 1) != 0) {
for (int i = right, lo = run[count - 1]; --i >= lo;
b[i] = a[i]
);
run[++last] = right;
}
int[] t = a; a = b; b = t;
}
} }
/** /**
...@@ -103,7 +201,7 @@ final class DualPivotQuicksort { ...@@ -103,7 +201,7 @@ final class DualPivotQuicksort {
private static void sort(int[] a, int left, int right, boolean leftmost) { private static void sort(int[] a, int left, int right, boolean leftmost) {
int length = right - left + 1; int length = right - left + 1;
// Use insertion sort on small arrays // Use insertion sort on tiny arrays
if (length < INSERTION_SORT_THRESHOLD) { if (length < INSERTION_SORT_THRESHOLD) {
if (leftmost) { if (leftmost) {
/* /*
...@@ -126,26 +224,24 @@ final class DualPivotQuicksort { ...@@ -126,26 +224,24 @@ final class DualPivotQuicksort {
* Skip the longest ascending sequence. * Skip the longest ascending sequence.
*/ */
do { do {
if (left++ >= right) { if (left >= right) {
return; return;
} }
} while (a[left - 1] <= a[left]); } while (a[++left] >= a[left - 1]);
/* /*
* Every element from adjoining part plays the role * Every element from adjoining part plays the role
* of sentinel, therefore this allows us to avoid the * of sentinel, therefore this allows us to avoid the
* left range check on each iteration. Moreover, we use * left range check on each iteration. Moreover, we use
* the best improved algorithm, so called pair insertion * the more optimized algorithm, so called pair insertion
* sort, which is faster than traditional implementation * sort, which is faster (in the context of Quicksort)
* in the context of Dual-Pivot Quicksort. * than traditional implementation of insertion sort.
*/ */
for (int k = left--; (left += 2) <= right; ) { for (int k = left; ++left <= right; k = ++left) {
int a1, a2; k = left - 1; int a1 = a[k], a2 = a[left];
if (a[k] < a[left]) { if (a1 < a2) {
a2 = a[k]; a1 = a[left]; a2 = a1; a1 = a[left];
} else {
a1 = a[k]; a2 = a[left];
} }
while (a1 < a[--k]) { while (a1 < a[--k]) {
a[k + 2] = a[k]; a[k + 2] = a[k];
...@@ -202,6 +298,11 @@ final class DualPivotQuicksort { ...@@ -202,6 +298,11 @@ final class DualPivotQuicksort {
} }
} }
// Pointers
int less = left; // The index of the first element of center part
int great = right; // The index before the first element of right part
if (a[e1] != a[e2] && a[e2] != a[e3] && a[e3] != a[e4] && a[e4] != a[e5]) {
/* /*
* Use the second and fourth of the five sorted elements as pivots. * Use the second and fourth of the five sorted elements as pivots.
* These values are inexpensive approximations of the first and * These values are inexpensive approximations of the first and
...@@ -210,11 +311,6 @@ final class DualPivotQuicksort { ...@@ -210,11 +311,6 @@ final class DualPivotQuicksort {
int pivot1 = a[e2]; int pivot1 = a[e2];
int pivot2 = a[e4]; int pivot2 = a[e4];
// Pointers
int less = left; // The index of the first element of center part
int great = right; // The index before the first element of right part
if (pivot1 != pivot2) {
/* /*
* The first and the last elements to be sorted are moved to the * The first and the last elements to be sorted are moved to the
* locations formerly occupied by the pivots. When partitioning * locations formerly occupied by the pivots. When partitioning
...@@ -259,7 +355,7 @@ final class DualPivotQuicksort { ...@@ -259,7 +355,7 @@ final class DualPivotQuicksort {
* of "a[i++] = b;" due to performance issue. * of "a[i++] = b;" due to performance issue.
*/ */
a[less] = ak; a[less] = ak;
less++; ++less;
} else if (ak > pivot2) { // Move a[k] to right part } else if (ak > pivot2) { // Move a[k] to right part
while (a[great] > pivot2) { while (a[great] > pivot2) {
if (great-- == k) { if (great-- == k) {
...@@ -269,7 +365,7 @@ final class DualPivotQuicksort { ...@@ -269,7 +365,7 @@ final class DualPivotQuicksort {
if (a[great] < pivot1) { // a[great] <= pivot2 if (a[great] < pivot1) { // a[great] <= pivot2
a[k] = a[less]; a[k] = a[less];
a[less] = a[great]; a[less] = a[great];
less++; ++less;
} else { // pivot1 <= a[great] <= pivot2 } else { // pivot1 <= a[great] <= pivot2
a[k] = a[great]; a[k] = a[great];
} }
...@@ -278,7 +374,7 @@ final class DualPivotQuicksort { ...@@ -278,7 +374,7 @@ final class DualPivotQuicksort {
* of "a[i--] = b;" due to performance issue. * of "a[i--] = b;" due to performance issue.
*/ */
a[great] = ak; a[great] = ak;
great--; --great;
} }
} }
...@@ -299,10 +395,11 @@ final class DualPivotQuicksort { ...@@ -299,10 +395,11 @@ final class DualPivotQuicksort {
* Skip elements, which are equal to pivot values. * Skip elements, which are equal to pivot values.
*/ */
while (a[less] == pivot1) { while (a[less] == pivot1) {
less++; ++less;
} }
while (a[great] == pivot2) { while (a[great] == pivot2) {
great--; --great;
} }
/* /*
...@@ -330,7 +427,7 @@ final class DualPivotQuicksort { ...@@ -330,7 +427,7 @@ final class DualPivotQuicksort {
if (ak == pivot1) { // Move a[k] to left part if (ak == pivot1) { // Move a[k] to left part
a[k] = a[less]; a[k] = a[less];
a[less] = ak; a[less] = ak;
less++; ++less;
} else if (ak == pivot2) { // Move a[k] to right part } else if (ak == pivot2) { // Move a[k] to right part
while (a[great] == pivot2) { while (a[great] == pivot2) {
if (great-- == k) { if (great-- == k) {
...@@ -348,12 +445,12 @@ final class DualPivotQuicksort { ...@@ -348,12 +445,12 @@ final class DualPivotQuicksort {
* accurate assignment a[less] = a[great]. * accurate assignment a[less] = a[great].
*/ */
a[less] = pivot1; a[less] = pivot1;
less++; ++less;
} else { // pivot1 < a[great] < pivot2 } else { // pivot1 < a[great] < pivot2
a[k] = a[great]; a[k] = a[great];
} }
a[great] = ak; a[great] = ak;
great--; --great;
} }
} }
} }
...@@ -361,7 +458,13 @@ final class DualPivotQuicksort { ...@@ -361,7 +458,13 @@ final class DualPivotQuicksort {
// Sort center part recursively // Sort center part recursively
sort(a, less, great, false); sort(a, less, great, false);
} else { // Pivots are equal } else { // Partitioning with one pivot
/*
* Use the third of the five sorted elements as pivot.
* This value is inexpensive approximation of the median.
*/
int pivot = a[e3];
/* /*
* Partitioning degenerates to the traditional 3-way * Partitioning degenerates to the traditional 3-way
* (or "Dutch National Flag") schema: * (or "Dutch National Flag") schema:
...@@ -383,35 +486,35 @@ final class DualPivotQuicksort { ...@@ -383,35 +486,35 @@ final class DualPivotQuicksort {
* Pointer k is the first index of ?-part. * Pointer k is the first index of ?-part.
*/ */
for (int k = less; k <= great; ++k) { for (int k = less; k <= great; ++k) {
if (a[k] == pivot1) { if (a[k] == pivot) {
continue; continue;
} }
int ak = a[k]; int ak = a[k];
if (ak < pivot1) { // Move a[k] to left part if (ak < pivot) { // Move a[k] to left part
a[k] = a[less]; a[k] = a[less];
a[less] = ak; a[less] = ak;
less++; ++less;
} else { // a[k] > pivot1 - Move a[k] to right part } else { // a[k] > pivot - Move a[k] to right part
while (a[great] > pivot1) { while (a[great] > pivot) {
great--; --great;
} }
if (a[great] < pivot1) { // a[great] <= pivot1 if (a[great] < pivot) { // a[great] <= pivot
a[k] = a[less]; a[k] = a[less];
a[less] = a[great]; a[less] = a[great];
less++; ++less;
} else { // a[great] == pivot1 } else { // a[great] == pivot
/* /*
* Even though a[great] equals to pivot1, the * Even though a[great] equals to pivot, the
* assignment a[k] = pivot1 may be incorrect, * assignment a[k] = pivot may be incorrect,
* if a[great] and pivot1 are floating-point * if a[great] and pivot are floating-point
* zeros of different signs. Therefore in float * zeros of different signs. Therefore in float
* and double sorting methods we have to use * and double sorting methods we have to use
* more accurate assignment a[k] = a[great]. * more accurate assignment a[k] = a[great].
*/ */
a[k] = pivot1; a[k] = pivot;
} }
a[great] = ak; a[great] = ak;
great--; --great;
} }
} }
...@@ -431,7 +534,7 @@ final class DualPivotQuicksort { ...@@ -431,7 +534,7 @@ final class DualPivotQuicksort {
* @param a the array to be sorted * @param a the array to be sorted
*/ */
public static void sort(long[] a) { public static void sort(long[] a) {
sort(a, 0, a.length - 1, true); sort(a, 0, a.length - 1);
} }
/** /**
...@@ -442,7 +545,89 @@ final class DualPivotQuicksort { ...@@ -442,7 +545,89 @@ final class DualPivotQuicksort {
* @param right the index of the last element, inclusive, to be sorted * @param right the index of the last element, inclusive, to be sorted
*/ */
public static void sort(long[] a, int left, int right) { public static void sort(long[] a, int left, int right) {
// Use Quicksort on small arrays
if (right - left < QUICKSORT_THRESHOLD) {
sort(a, left, right, true); sort(a, left, right, true);
return;
}
/*
* Index run[i] is the start of i-th run
* (ascending or descending sequence).
*/
int[] run = new int[MAX_RUN_COUNT];
int count = 0; run[0] = left;
// Check if the array is nearly sorted
for (int k = left; k < right; run[count] = k) {
if (a[k] < a[k + 1]) { // ascending
while (++k <= right && a[k - 1] <= a[k]);
} else if (a[k] > a[k + 1]) { // descending
while (++k <= right && a[k - 1] >= a[k]);
for (int lo = run[count] - 1, hi = k; ++lo < --hi; ) {
long t = a[lo]; a[lo] = a[hi]; a[hi] = t;
}
} else { // equal
for (int m = MAX_RUN_LENGTH; ++k <= right && a[k - 1] == a[k]; ) {
if (--m == 0) {
sort(a, left, right, true);
return;
}
}
}
/*
* The array is not highly structured,
* use Quicksort instead of merge sort.
*/
if (++count == MAX_RUN_COUNT) {
sort(a, left, right, true);
return;
}
}
// Check special cases
if (run[count] == right++) { // The last run contains one element
run[++count] = right;
} else if (count == 1) { // The array is already sorted
return;
}
/*
* Create temporary array, which is used for merging.
* Implementation note: variable "right" is increased by 1.
*/
long[] b; byte odd = 0;
for (int n = 1; (n <<= 1) < count; odd ^= 1);
if (odd == 0) {
b = a; a = new long[b.length];
for (int i = left - 1; ++i < right; a[i] = b[i]);
} else {
b = new long[a.length];
}
// Merging
for (int last; count > 1; count = last) {
for (int k = (last = 0) + 2; k <= count; k += 2) {
int hi = run[k], mi = run[k - 1];
for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) {
if (q >= hi || p < mi && a[p] <= a[q]) {
b[i] = a[p++];
} else {
b[i] = a[q++];
}
}
run[++last] = hi;
}
if ((count & 1) != 0) {
for (int i = right, lo = run[count - 1]; --i >= lo;
b[i] = a[i]
);
run[++last] = right;
}
long[] t = a; a = b; b = t;
}
} }
/** /**
...@@ -456,7 +641,7 @@ final class DualPivotQuicksort { ...@@ -456,7 +641,7 @@ final class DualPivotQuicksort {
private static void sort(long[] a, int left, int right, boolean leftmost) { private static void sort(long[] a, int left, int right, boolean leftmost) {
int length = right - left + 1; int length = right - left + 1;
// Use insertion sort on small arrays // Use insertion sort on tiny arrays
if (length < INSERTION_SORT_THRESHOLD) { if (length < INSERTION_SORT_THRESHOLD) {
if (leftmost) { if (leftmost) {
/* /*
...@@ -479,26 +664,24 @@ final class DualPivotQuicksort { ...@@ -479,26 +664,24 @@ final class DualPivotQuicksort {
* Skip the longest ascending sequence. * Skip the longest ascending sequence.
*/ */
do { do {
if (left++ >= right) { if (left >= right) {
return; return;
} }
} while (a[left - 1] <= a[left]); } while (a[++left] >= a[left - 1]);
/* /*
* Every element from adjoining part plays the role * Every element from adjoining part plays the role
* of sentinel, therefore this allows us to avoid the * of sentinel, therefore this allows us to avoid the
* left range check on each iteration. Moreover, we use * left range check on each iteration. Moreover, we use
* the best improved algorithm, so called pair insertion * the more optimized algorithm, so called pair insertion
* sort, which is faster than traditional implementation * sort, which is faster (in the context of Quicksort)
* in the context of Dual-Pivot Quicksort. * than traditional implementation of insertion sort.
*/ */
for (int k = left--; (left += 2) <= right; ) { for (int k = left; ++left <= right; k = ++left) {
long a1, a2; k = left - 1; long a1 = a[k], a2 = a[left];
if (a[k] < a[left]) { if (a1 < a2) {
a2 = a[k]; a1 = a[left]; a2 = a1; a1 = a[left];
} else {
a1 = a[k]; a2 = a[left];
} }
while (a1 < a[--k]) { while (a1 < a[--k]) {
a[k + 2] = a[k]; a[k + 2] = a[k];
...@@ -555,6 +738,11 @@ final class DualPivotQuicksort { ...@@ -555,6 +738,11 @@ final class DualPivotQuicksort {
} }
} }
// Pointers
int less = left; // The index of the first element of center part
int great = right; // The index before the first element of right part
if (a[e1] != a[e2] && a[e2] != a[e3] && a[e3] != a[e4] && a[e4] != a[e5]) {
/* /*
* Use the second and fourth of the five sorted elements as pivots. * Use the second and fourth of the five sorted elements as pivots.
* These values are inexpensive approximations of the first and * These values are inexpensive approximations of the first and
...@@ -563,11 +751,6 @@ final class DualPivotQuicksort { ...@@ -563,11 +751,6 @@ final class DualPivotQuicksort {
long pivot1 = a[e2]; long pivot1 = a[e2];
long pivot2 = a[e4]; long pivot2 = a[e4];
// Pointers
int less = left; // The index of the first element of center part
int great = right; // The index before the first element of right part
if (pivot1 != pivot2) {
/* /*
* The first and the last elements to be sorted are moved to the * The first and the last elements to be sorted are moved to the
* locations formerly occupied by the pivots. When partitioning * locations formerly occupied by the pivots. When partitioning
...@@ -612,7 +795,7 @@ final class DualPivotQuicksort { ...@@ -612,7 +795,7 @@ final class DualPivotQuicksort {
* of "a[i++] = b;" due to performance issue. * of "a[i++] = b;" due to performance issue.
*/ */
a[less] = ak; a[less] = ak;
less++; ++less;
} else if (ak > pivot2) { // Move a[k] to right part } else if (ak > pivot2) { // Move a[k] to right part
while (a[great] > pivot2) { while (a[great] > pivot2) {
if (great-- == k) { if (great-- == k) {
...@@ -622,7 +805,7 @@ final class DualPivotQuicksort { ...@@ -622,7 +805,7 @@ final class DualPivotQuicksort {
if (a[great] < pivot1) { // a[great] <= pivot2 if (a[great] < pivot1) { // a[great] <= pivot2
a[k] = a[less]; a[k] = a[less];
a[less] = a[great]; a[less] = a[great];
less++; ++less;
} else { // pivot1 <= a[great] <= pivot2 } else { // pivot1 <= a[great] <= pivot2
a[k] = a[great]; a[k] = a[great];
} }
...@@ -631,7 +814,7 @@ final class DualPivotQuicksort { ...@@ -631,7 +814,7 @@ final class DualPivotQuicksort {
* of "a[i--] = b;" due to performance issue. * of "a[i--] = b;" due to performance issue.
*/ */
a[great] = ak; a[great] = ak;
great--; --great;
} }
} }
...@@ -652,10 +835,11 @@ final class DualPivotQuicksort { ...@@ -652,10 +835,11 @@ final class DualPivotQuicksort {
* Skip elements, which are equal to pivot values. * Skip elements, which are equal to pivot values.
*/ */
while (a[less] == pivot1) { while (a[less] == pivot1) {
less++; ++less;
} }
while (a[great] == pivot2) { while (a[great] == pivot2) {
great--; --great;
} }
/* /*
...@@ -683,7 +867,7 @@ final class DualPivotQuicksort { ...@@ -683,7 +867,7 @@ final class DualPivotQuicksort {
if (ak == pivot1) { // Move a[k] to left part if (ak == pivot1) { // Move a[k] to left part
a[k] = a[less]; a[k] = a[less];
a[less] = ak; a[less] = ak;
less++; ++less;
} else if (ak == pivot2) { // Move a[k] to right part } else if (ak == pivot2) { // Move a[k] to right part
while (a[great] == pivot2) { while (a[great] == pivot2) {
if (great-- == k) { if (great-- == k) {
...@@ -701,12 +885,12 @@ final class DualPivotQuicksort { ...@@ -701,12 +885,12 @@ final class DualPivotQuicksort {
* accurate assignment a[less] = a[great]. * accurate assignment a[less] = a[great].
*/ */
a[less] = pivot1; a[less] = pivot1;
less++; ++less;
} else { // pivot1 < a[great] < pivot2 } else { // pivot1 < a[great] < pivot2
a[k] = a[great]; a[k] = a[great];
} }
a[great] = ak; a[great] = ak;
great--; --great;
} }
} }
} }
...@@ -714,7 +898,13 @@ final class DualPivotQuicksort { ...@@ -714,7 +898,13 @@ final class DualPivotQuicksort {
// Sort center part recursively // Sort center part recursively
sort(a, less, great, false); sort(a, less, great, false);
} else { // Pivots are equal } else { // Partitioning with one pivot
/*
* Use the third of the five sorted elements as pivot.
* This value is inexpensive approximation of the median.
*/
long pivot = a[e3];
/* /*
* Partitioning degenerates to the traditional 3-way * Partitioning degenerates to the traditional 3-way
* (or "Dutch National Flag") schema: * (or "Dutch National Flag") schema:
...@@ -736,35 +926,35 @@ final class DualPivotQuicksort { ...@@ -736,35 +926,35 @@ final class DualPivotQuicksort {
* Pointer k is the first index of ?-part. * Pointer k is the first index of ?-part.
*/ */
for (int k = less; k <= great; ++k) { for (int k = less; k <= great; ++k) {
if (a[k] == pivot1) { if (a[k] == pivot) {
continue; continue;
} }
long ak = a[k]; long ak = a[k];
if (ak < pivot1) { // Move a[k] to left part if (ak < pivot) { // Move a[k] to left part
a[k] = a[less]; a[k] = a[less];
a[less] = ak; a[less] = ak;
less++; ++less;
} else { // a[k] > pivot1 - Move a[k] to right part } else { // a[k] > pivot - Move a[k] to right part
while (a[great] > pivot1) { while (a[great] > pivot) {
great--; --great;
} }
if (a[great] < pivot1) { // a[great] <= pivot1 if (a[great] < pivot) { // a[great] <= pivot
a[k] = a[less]; a[k] = a[less];
a[less] = a[great]; a[less] = a[great];
less++; ++less;
} else { // a[great] == pivot1 } else { // a[great] == pivot
/* /*
* Even though a[great] equals to pivot1, the * Even though a[great] equals to pivot, the
* assignment a[k] = pivot1 may be incorrect, * assignment a[k] = pivot may be incorrect,
* if a[great] and pivot1 are floating-point * if a[great] and pivot are floating-point
* zeros of different signs. Therefore in float * zeros of different signs. Therefore in float
* and double sorting methods we have to use * and double sorting methods we have to use
* more accurate assignment a[k] = a[great]. * more accurate assignment a[k] = a[great].
*/ */
a[k] = pivot1; a[k] = pivot;
} }
a[great] = ak; a[great] = ak;
great--; --great;
} }
} }
...@@ -799,9 +989,9 @@ final class DualPivotQuicksort { ...@@ -799,9 +989,9 @@ final class DualPivotQuicksort {
if (right - left > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) { if (right - left > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) {
int[] count = new int[NUM_SHORT_VALUES]; int[] count = new int[NUM_SHORT_VALUES];
for (int i = left - 1; ++i <= right; ) { for (int i = left - 1; ++i <= right;
count[a[i] - Short.MIN_VALUE]++; count[a[i] - Short.MIN_VALUE]++
} );
for (int i = NUM_SHORT_VALUES, k = right + 1; k > left; ) { for (int i = NUM_SHORT_VALUES, k = right + 1; k > left; ) {
while (count[--i] == 0); while (count[--i] == 0);
short value = (short) (i + Short.MIN_VALUE); short value = (short) (i + Short.MIN_VALUE);
...@@ -812,13 +1002,106 @@ final class DualPivotQuicksort { ...@@ -812,13 +1002,106 @@ final class DualPivotQuicksort {
} while (--s > 0); } while (--s > 0);
} }
} else { // Use Dual-Pivot Quicksort on small arrays } else { // Use Dual-Pivot Quicksort on small arrays
sort(a, left, right, true); doSort(a, left, right);
} }
} }
/** The number of distinct short values. */ /** The number of distinct short values. */
private static final int NUM_SHORT_VALUES = 1 << 16; private static final int NUM_SHORT_VALUES = 1 << 16;
/**
* Sorts the specified range of the array.
*
* @param a the array to be sorted
* @param left the index of the first element, inclusive, to be sorted
* @param right the index of the last element, inclusive, to be sorted
*/
private static void doSort(short[] a, int left, int right) {
// Use Quicksort on small arrays
if (right - left < QUICKSORT_THRESHOLD) {
sort(a, left, right, true);
return;
}
/*
* Index run[i] is the start of i-th run
* (ascending or descending sequence).
*/
int[] run = new int[MAX_RUN_COUNT];
int count = 0; run[0] = left;
// Check if the array is nearly sorted
for (int k = left; k < right; run[count] = k) {
if (a[k] < a[k + 1]) { // ascending
while (++k <= right && a[k - 1] <= a[k]);
} else if (a[k] > a[k + 1]) { // descending
while (++k <= right && a[k - 1] >= a[k]);
for (int lo = run[count] - 1, hi = k; ++lo < --hi; ) {
short t = a[lo]; a[lo] = a[hi]; a[hi] = t;
}
} else { // equal
for (int m = MAX_RUN_LENGTH; ++k <= right && a[k - 1] == a[k]; ) {
if (--m == 0) {
sort(a, left, right, true);
return;
}
}
}
/*
* The array is not highly structured,
* use Quicksort instead of merge sort.
*/
if (++count == MAX_RUN_COUNT) {
sort(a, left, right, true);
return;
}
}
// Check special cases
if (run[count] == right++) { // The last run contains one element
run[++count] = right;
} else if (count == 1) { // The array is already sorted
return;
}
/*
* Create temporary array, which is used for merging.
* Implementation note: variable "right" is increased by 1.
*/
short[] b; byte odd = 0;
for (int n = 1; (n <<= 1) < count; odd ^= 1);
if (odd == 0) {
b = a; a = new short[b.length];
for (int i = left - 1; ++i < right; a[i] = b[i]);
} else {
b = new short[a.length];
}
// Merging
for (int last; count > 1; count = last) {
for (int k = (last = 0) + 2; k <= count; k += 2) {
int hi = run[k], mi = run[k - 1];
for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) {
if (q >= hi || p < mi && a[p] <= a[q]) {
b[i] = a[p++];
} else {
b[i] = a[q++];
}
}
run[++last] = hi;
}
if ((count & 1) != 0) {
for (int i = right, lo = run[count - 1]; --i >= lo;
b[i] = a[i]
);
run[++last] = right;
}
short[] t = a; a = b; b = t;
}
}
/** /**
* Sorts the specified range of the array by Dual-Pivot Quicksort. * Sorts the specified range of the array by Dual-Pivot Quicksort.
* *
...@@ -827,10 +1110,10 @@ final class DualPivotQuicksort { ...@@ -827,10 +1110,10 @@ final class DualPivotQuicksort {
* @param right the index of the last element, inclusive, to be sorted * @param right the index of the last element, inclusive, to be sorted
* @param leftmost indicates if this part is the leftmost in the range * @param leftmost indicates if this part is the leftmost in the range
*/ */
private static void sort(short[] a, int left, int right,boolean leftmost) { private static void sort(short[] a, int left, int right, boolean leftmost) {
int length = right - left + 1; int length = right - left + 1;
// Use insertion sort on small arrays // Use insertion sort on tiny arrays
if (length < INSERTION_SORT_THRESHOLD) { if (length < INSERTION_SORT_THRESHOLD) {
if (leftmost) { if (leftmost) {
/* /*
...@@ -853,26 +1136,24 @@ final class DualPivotQuicksort { ...@@ -853,26 +1136,24 @@ final class DualPivotQuicksort {
* Skip the longest ascending sequence. * Skip the longest ascending sequence.
*/ */
do { do {
if (left++ >= right) { if (left >= right) {
return; return;
} }
} while (a[left - 1] <= a[left]); } while (a[++left] >= a[left - 1]);
/* /*
* Every element from adjoining part plays the role * Every element from adjoining part plays the role
* of sentinel, therefore this allows us to avoid the * of sentinel, therefore this allows us to avoid the
* left range check on each iteration. Moreover, we use * left range check on each iteration. Moreover, we use
* the best improved algorithm, so called pair insertion * the more optimized algorithm, so called pair insertion
* sort, which is faster than traditional implementation * sort, which is faster (in the context of Quicksort)
* in the context of Dual-Pivot Quicksort. * than traditional implementation of insertion sort.
*/ */
for (int k = left--; (left += 2) <= right; ) { for (int k = left; ++left <= right; k = ++left) {
short a1, a2; k = left - 1; short a1 = a[k], a2 = a[left];
if (a[k] < a[left]) { if (a1 < a2) {
a2 = a[k]; a1 = a[left]; a2 = a1; a1 = a[left];
} else {
a1 = a[k]; a2 = a[left];
} }
while (a1 < a[--k]) { while (a1 < a[--k]) {
a[k + 2] = a[k]; a[k + 2] = a[k];
...@@ -929,6 +1210,11 @@ final class DualPivotQuicksort { ...@@ -929,6 +1210,11 @@ final class DualPivotQuicksort {
} }
} }
// Pointers
int less = left; // The index of the first element of center part
int great = right; // The index before the first element of right part
if (a[e1] != a[e2] && a[e2] != a[e3] && a[e3] != a[e4] && a[e4] != a[e5]) {
/* /*
* Use the second and fourth of the five sorted elements as pivots. * Use the second and fourth of the five sorted elements as pivots.
* These values are inexpensive approximations of the first and * These values are inexpensive approximations of the first and
...@@ -937,11 +1223,6 @@ final class DualPivotQuicksort { ...@@ -937,11 +1223,6 @@ final class DualPivotQuicksort {
short pivot1 = a[e2]; short pivot1 = a[e2];
short pivot2 = a[e4]; short pivot2 = a[e4];
// Pointers
int less = left; // The index of the first element of center part
int great = right; // The index before the first element of right part
if (pivot1 != pivot2) {
/* /*
* The first and the last elements to be sorted are moved to the * The first and the last elements to be sorted are moved to the
* locations formerly occupied by the pivots. When partitioning * locations formerly occupied by the pivots. When partitioning
...@@ -986,7 +1267,7 @@ final class DualPivotQuicksort { ...@@ -986,7 +1267,7 @@ final class DualPivotQuicksort {
* of "a[i++] = b;" due to performance issue. * of "a[i++] = b;" due to performance issue.
*/ */
a[less] = ak; a[less] = ak;
less++; ++less;
} else if (ak > pivot2) { // Move a[k] to right part } else if (ak > pivot2) { // Move a[k] to right part
while (a[great] > pivot2) { while (a[great] > pivot2) {
if (great-- == k) { if (great-- == k) {
...@@ -996,7 +1277,7 @@ final class DualPivotQuicksort { ...@@ -996,7 +1277,7 @@ final class DualPivotQuicksort {
if (a[great] < pivot1) { // a[great] <= pivot2 if (a[great] < pivot1) { // a[great] <= pivot2
a[k] = a[less]; a[k] = a[less];
a[less] = a[great]; a[less] = a[great];
less++; ++less;
} else { // pivot1 <= a[great] <= pivot2 } else { // pivot1 <= a[great] <= pivot2
a[k] = a[great]; a[k] = a[great];
} }
...@@ -1005,7 +1286,7 @@ final class DualPivotQuicksort { ...@@ -1005,7 +1286,7 @@ final class DualPivotQuicksort {
* of "a[i--] = b;" due to performance issue. * of "a[i--] = b;" due to performance issue.
*/ */
a[great] = ak; a[great] = ak;
great--; --great;
} }
} }
...@@ -1026,10 +1307,11 @@ final class DualPivotQuicksort { ...@@ -1026,10 +1307,11 @@ final class DualPivotQuicksort {
* Skip elements, which are equal to pivot values. * Skip elements, which are equal to pivot values.
*/ */
while (a[less] == pivot1) { while (a[less] == pivot1) {
less++; ++less;
} }
while (a[great] == pivot2) { while (a[great] == pivot2) {
great--; --great;
} }
/* /*
...@@ -1057,7 +1339,7 @@ final class DualPivotQuicksort { ...@@ -1057,7 +1339,7 @@ final class DualPivotQuicksort {
if (ak == pivot1) { // Move a[k] to left part if (ak == pivot1) { // Move a[k] to left part
a[k] = a[less]; a[k] = a[less];
a[less] = ak; a[less] = ak;
less++; ++less;
} else if (ak == pivot2) { // Move a[k] to right part } else if (ak == pivot2) { // Move a[k] to right part
while (a[great] == pivot2) { while (a[great] == pivot2) {
if (great-- == k) { if (great-- == k) {
...@@ -1075,12 +1357,12 @@ final class DualPivotQuicksort { ...@@ -1075,12 +1357,12 @@ final class DualPivotQuicksort {
* accurate assignment a[less] = a[great]. * accurate assignment a[less] = a[great].
*/ */
a[less] = pivot1; a[less] = pivot1;
less++; ++less;
} else { // pivot1 < a[great] < pivot2 } else { // pivot1 < a[great] < pivot2
a[k] = a[great]; a[k] = a[great];
} }
a[great] = ak; a[great] = ak;
great--; --great;
} }
} }
} }
...@@ -1088,7 +1370,13 @@ final class DualPivotQuicksort { ...@@ -1088,7 +1370,13 @@ final class DualPivotQuicksort {
// Sort center part recursively // Sort center part recursively
sort(a, less, great, false); sort(a, less, great, false);
} else { // Pivots are equal } else { // Partitioning with one pivot
/*
* Use the third of the five sorted elements as pivot.
* This value is inexpensive approximation of the median.
*/
short pivot = a[e3];
/* /*
* Partitioning degenerates to the traditional 3-way * Partitioning degenerates to the traditional 3-way
* (or "Dutch National Flag") schema: * (or "Dutch National Flag") schema:
...@@ -1110,35 +1398,35 @@ final class DualPivotQuicksort { ...@@ -1110,35 +1398,35 @@ final class DualPivotQuicksort {
* Pointer k is the first index of ?-part. * Pointer k is the first index of ?-part.
*/ */
for (int k = less; k <= great; ++k) { for (int k = less; k <= great; ++k) {
if (a[k] == pivot1) { if (a[k] == pivot) {
continue; continue;
} }
short ak = a[k]; short ak = a[k];
if (ak < pivot1) { // Move a[k] to left part if (ak < pivot) { // Move a[k] to left part
a[k] = a[less]; a[k] = a[less];
a[less] = ak; a[less] = ak;
less++; ++less;
} else { // a[k] > pivot1 - Move a[k] to right part } else { // a[k] > pivot - Move a[k] to right part
while (a[great] > pivot1) { while (a[great] > pivot) {
great--; --great;
} }
if (a[great] < pivot1) { // a[great] <= pivot1 if (a[great] < pivot) { // a[great] <= pivot
a[k] = a[less]; a[k] = a[less];
a[less] = a[great]; a[less] = a[great];
less++; ++less;
} else { // a[great] == pivot1 } else { // a[great] == pivot
/* /*
* Even though a[great] equals to pivot1, the * Even though a[great] equals to pivot, the
* assignment a[k] = pivot1 may be incorrect, * assignment a[k] = pivot may be incorrect,
* if a[great] and pivot1 are floating-point * if a[great] and pivot are floating-point
* zeros of different signs. Therefore in float * zeros of different signs. Therefore in float
* and double sorting methods we have to use * and double sorting methods we have to use
* more accurate assignment a[k] = a[great]. * more accurate assignment a[k] = a[great].
*/ */
a[k] = pivot1; a[k] = pivot;
} }
a[great] = ak; a[great] = ak;
great--; --great;
} }
} }
...@@ -1173,9 +1461,9 @@ final class DualPivotQuicksort { ...@@ -1173,9 +1461,9 @@ final class DualPivotQuicksort {
if (right - left > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) { if (right - left > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) {
int[] count = new int[NUM_CHAR_VALUES]; int[] count = new int[NUM_CHAR_VALUES];
for (int i = left - 1; ++i <= right; ) { for (int i = left - 1; ++i <= right;
count[a[i]]++; count[a[i]]++
} );
for (int i = NUM_CHAR_VALUES, k = right + 1; k > left; ) { for (int i = NUM_CHAR_VALUES, k = right + 1; k > left; ) {
while (count[--i] == 0); while (count[--i] == 0);
char value = (char) i; char value = (char) i;
...@@ -1186,13 +1474,106 @@ final class DualPivotQuicksort { ...@@ -1186,13 +1474,106 @@ final class DualPivotQuicksort {
} while (--s > 0); } while (--s > 0);
} }
} else { // Use Dual-Pivot Quicksort on small arrays } else { // Use Dual-Pivot Quicksort on small arrays
sort(a, left, right, true); doSort(a, left, right);
} }
} }
/** The number of distinct char values. */ /** The number of distinct char values. */
private static final int NUM_CHAR_VALUES = 1 << 16; private static final int NUM_CHAR_VALUES = 1 << 16;
/**
* Sorts the specified range of the array.
*
* @param a the array to be sorted
* @param left the index of the first element, inclusive, to be sorted
* @param right the index of the last element, inclusive, to be sorted
*/
private static void doSort(char[] a, int left, int right) {
// Use Quicksort on small arrays
if (right - left < QUICKSORT_THRESHOLD) {
sort(a, left, right, true);
return;
}
/*
* Index run[i] is the start of i-th run
* (ascending or descending sequence).
*/
int[] run = new int[MAX_RUN_COUNT];
int count = 0; run[0] = left;
// Check if the array is nearly sorted
for (int k = left; k < right; run[count] = k) {
if (a[k] < a[k + 1]) { // ascending
while (++k <= right && a[k - 1] <= a[k]);
} else if (a[k] > a[k + 1]) { // descending
while (++k <= right && a[k - 1] >= a[k]);
for (int lo = run[count] - 1, hi = k; ++lo < --hi; ) {
char t = a[lo]; a[lo] = a[hi]; a[hi] = t;
}
} else { // equal
for (int m = MAX_RUN_LENGTH; ++k <= right && a[k - 1] == a[k]; ) {
if (--m == 0) {
sort(a, left, right, true);
return;
}
}
}
/*
* The array is not highly structured,
* use Quicksort instead of merge sort.
*/
if (++count == MAX_RUN_COUNT) {
sort(a, left, right, true);
return;
}
}
// Check special cases
if (run[count] == right++) { // The last run contains one element
run[++count] = right;
} else if (count == 1) { // The array is already sorted
return;
}
/*
* Create temporary array, which is used for merging.
* Implementation note: variable "right" is increased by 1.
*/
char[] b; byte odd = 0;
for (int n = 1; (n <<= 1) < count; odd ^= 1);
if (odd == 0) {
b = a; a = new char[b.length];
for (int i = left - 1; ++i < right; a[i] = b[i]);
} else {
b = new char[a.length];
}
// Merging
for (int last; count > 1; count = last) {
for (int k = (last = 0) + 2; k <= count; k += 2) {
int hi = run[k], mi = run[k - 1];
for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) {
if (q >= hi || p < mi && a[p] <= a[q]) {
b[i] = a[p++];
} else {
b[i] = a[q++];
}
}
run[++last] = hi;
}
if ((count & 1) != 0) {
for (int i = right, lo = run[count - 1]; --i >= lo;
b[i] = a[i]
);
run[++last] = right;
}
char[] t = a; a = b; b = t;
}
}
/** /**
* Sorts the specified range of the array by Dual-Pivot Quicksort. * Sorts the specified range of the array by Dual-Pivot Quicksort.
* *
...@@ -1204,7 +1585,7 @@ final class DualPivotQuicksort { ...@@ -1204,7 +1585,7 @@ final class DualPivotQuicksort {
private static void sort(char[] a, int left, int right, boolean leftmost) { private static void sort(char[] a, int left, int right, boolean leftmost) {
int length = right - left + 1; int length = right - left + 1;
// Use insertion sort on small arrays // Use insertion sort on tiny arrays
if (length < INSERTION_SORT_THRESHOLD) { if (length < INSERTION_SORT_THRESHOLD) {
if (leftmost) { if (leftmost) {
/* /*
...@@ -1227,26 +1608,24 @@ final class DualPivotQuicksort { ...@@ -1227,26 +1608,24 @@ final class DualPivotQuicksort {
* Skip the longest ascending sequence. * Skip the longest ascending sequence.
*/ */
do { do {
if (left++ >= right) { if (left >= right) {
return; return;
} }
} while (a[left - 1] <= a[left]); } while (a[++left] >= a[left - 1]);
/* /*
* Every element from adjoining part plays the role * Every element from adjoining part plays the role
* of sentinel, therefore this allows us to avoid the * of sentinel, therefore this allows us to avoid the
* left range check on each iteration. Moreover, we use * left range check on each iteration. Moreover, we use
* the best improved algorithm, so called pair insertion * the more optimized algorithm, so called pair insertion
* sort, which is faster than traditional implementation * sort, which is faster (in the context of Quicksort)
* in the context of Dual-Pivot Quicksort. * than traditional implementation of insertion sort.
*/ */
for (int k = left--; (left += 2) <= right; ) { for (int k = left; ++left <= right; k = ++left) {
char a1, a2; k = left - 1; char a1 = a[k], a2 = a[left];
if (a[k] < a[left]) { if (a1 < a2) {
a2 = a[k]; a1 = a[left]; a2 = a1; a1 = a[left];
} else {
a1 = a[k]; a2 = a[left];
} }
while (a1 < a[--k]) { while (a1 < a[--k]) {
a[k + 2] = a[k]; a[k + 2] = a[k];
...@@ -1303,6 +1682,11 @@ final class DualPivotQuicksort { ...@@ -1303,6 +1682,11 @@ final class DualPivotQuicksort {
} }
} }
// Pointers
int less = left; // The index of the first element of center part
int great = right; // The index before the first element of right part
if (a[e1] != a[e2] && a[e2] != a[e3] && a[e3] != a[e4] && a[e4] != a[e5]) {
/* /*
* Use the second and fourth of the five sorted elements as pivots. * Use the second and fourth of the five sorted elements as pivots.
* These values are inexpensive approximations of the first and * These values are inexpensive approximations of the first and
...@@ -1311,11 +1695,6 @@ final class DualPivotQuicksort { ...@@ -1311,11 +1695,6 @@ final class DualPivotQuicksort {
char pivot1 = a[e2]; char pivot1 = a[e2];
char pivot2 = a[e4]; char pivot2 = a[e4];
// Pointers
int less = left; // The index of the first element of center part
int great = right; // The index before the first element of right part
if (pivot1 != pivot2) {
/* /*
* The first and the last elements to be sorted are moved to the * The first and the last elements to be sorted are moved to the
* locations formerly occupied by the pivots. When partitioning * locations formerly occupied by the pivots. When partitioning
...@@ -1360,7 +1739,7 @@ final class DualPivotQuicksort { ...@@ -1360,7 +1739,7 @@ final class DualPivotQuicksort {
* of "a[i++] = b;" due to performance issue. * of "a[i++] = b;" due to performance issue.
*/ */
a[less] = ak; a[less] = ak;
less++; ++less;
} else if (ak > pivot2) { // Move a[k] to right part } else if (ak > pivot2) { // Move a[k] to right part
while (a[great] > pivot2) { while (a[great] > pivot2) {
if (great-- == k) { if (great-- == k) {
...@@ -1370,7 +1749,7 @@ final class DualPivotQuicksort { ...@@ -1370,7 +1749,7 @@ final class DualPivotQuicksort {
if (a[great] < pivot1) { // a[great] <= pivot2 if (a[great] < pivot1) { // a[great] <= pivot2
a[k] = a[less]; a[k] = a[less];
a[less] = a[great]; a[less] = a[great];
less++; ++less;
} else { // pivot1 <= a[great] <= pivot2 } else { // pivot1 <= a[great] <= pivot2
a[k] = a[great]; a[k] = a[great];
} }
...@@ -1379,7 +1758,7 @@ final class DualPivotQuicksort { ...@@ -1379,7 +1758,7 @@ final class DualPivotQuicksort {
* of "a[i--] = b;" due to performance issue. * of "a[i--] = b;" due to performance issue.
*/ */
a[great] = ak; a[great] = ak;
great--; --great;
} }
} }
...@@ -1400,10 +1779,11 @@ final class DualPivotQuicksort { ...@@ -1400,10 +1779,11 @@ final class DualPivotQuicksort {
* Skip elements, which are equal to pivot values. * Skip elements, which are equal to pivot values.
*/ */
while (a[less] == pivot1) { while (a[less] == pivot1) {
less++; ++less;
} }
while (a[great] == pivot2) { while (a[great] == pivot2) {
great--; --great;
} }
/* /*
...@@ -1431,7 +1811,7 @@ final class DualPivotQuicksort { ...@@ -1431,7 +1811,7 @@ final class DualPivotQuicksort {
if (ak == pivot1) { // Move a[k] to left part if (ak == pivot1) { // Move a[k] to left part
a[k] = a[less]; a[k] = a[less];
a[less] = ak; a[less] = ak;
less++; ++less;
} else if (ak == pivot2) { // Move a[k] to right part } else if (ak == pivot2) { // Move a[k] to right part
while (a[great] == pivot2) { while (a[great] == pivot2) {
if (great-- == k) { if (great-- == k) {
...@@ -1449,12 +1829,12 @@ final class DualPivotQuicksort { ...@@ -1449,12 +1829,12 @@ final class DualPivotQuicksort {
* accurate assignment a[less] = a[great]. * accurate assignment a[less] = a[great].
*/ */
a[less] = pivot1; a[less] = pivot1;
less++; ++less;
} else { // pivot1 < a[great] < pivot2 } else { // pivot1 < a[great] < pivot2
a[k] = a[great]; a[k] = a[great];
} }
a[great] = ak; a[great] = ak;
great--; --great;
} }
} }
} }
...@@ -1462,7 +1842,13 @@ final class DualPivotQuicksort { ...@@ -1462,7 +1842,13 @@ final class DualPivotQuicksort {
// Sort center part recursively // Sort center part recursively
sort(a, less, great, false); sort(a, less, great, false);
} else { // Pivots are equal } else { // Partitioning with one pivot
/*
* Use the third of the five sorted elements as pivot.
* This value is inexpensive approximation of the median.
*/
char pivot = a[e3];
/* /*
* Partitioning degenerates to the traditional 3-way * Partitioning degenerates to the traditional 3-way
* (or "Dutch National Flag") schema: * (or "Dutch National Flag") schema:
...@@ -1484,35 +1870,35 @@ final class DualPivotQuicksort { ...@@ -1484,35 +1870,35 @@ final class DualPivotQuicksort {
* Pointer k is the first index of ?-part. * Pointer k is the first index of ?-part.
*/ */
for (int k = less; k <= great; ++k) { for (int k = less; k <= great; ++k) {
if (a[k] == pivot1) { if (a[k] == pivot) {
continue; continue;
} }
char ak = a[k]; char ak = a[k];
if (ak < pivot1) { // Move a[k] to left part if (ak < pivot) { // Move a[k] to left part
a[k] = a[less]; a[k] = a[less];
a[less] = ak; a[less] = ak;
less++; ++less;
} else { // a[k] > pivot1 - Move a[k] to right part } else { // a[k] > pivot - Move a[k] to right part
while (a[great] > pivot1) { while (a[great] > pivot) {
great--; --great;
} }
if (a[great] < pivot1) { // a[great] <= pivot1 if (a[great] < pivot) { // a[great] <= pivot
a[k] = a[less]; a[k] = a[less];
a[less] = a[great]; a[less] = a[great];
less++; ++less;
} else { // a[great] == pivot1 } else { // a[great] == pivot
/* /*
* Even though a[great] equals to pivot1, the * Even though a[great] equals to pivot, the
* assignment a[k] = pivot1 may be incorrect, * assignment a[k] = pivot may be incorrect,
* if a[great] and pivot1 are floating-point * if a[great] and pivot are floating-point
* zeros of different signs. Therefore in float * zeros of different signs. Therefore in float
* and double sorting methods we have to use * and double sorting methods we have to use
* more accurate assignment a[k] = a[great]. * more accurate assignment a[k] = a[great].
*/ */
a[k] = pivot1; a[k] = pivot;
} }
a[great] = ak; a[great] = ak;
great--; --great;
} }
} }
...@@ -1550,9 +1936,9 @@ final class DualPivotQuicksort { ...@@ -1550,9 +1936,9 @@ final class DualPivotQuicksort {
if (right - left > COUNTING_SORT_THRESHOLD_FOR_BYTE) { if (right - left > COUNTING_SORT_THRESHOLD_FOR_BYTE) {
int[] count = new int[NUM_BYTE_VALUES]; int[] count = new int[NUM_BYTE_VALUES];
for (int i = left - 1; ++i <= right; ) { for (int i = left - 1; ++i <= right;
count[a[i] - Byte.MIN_VALUE]++; count[a[i] - Byte.MIN_VALUE]++
} );
for (int i = NUM_BYTE_VALUES, k = right + 1; k > left; ) { for (int i = NUM_BYTE_VALUES, k = right + 1; k > left; ) {
while (count[--i] == 0); while (count[--i] == 0);
byte value = (byte) (i + Byte.MIN_VALUE); byte value = (byte) (i + Byte.MIN_VALUE);
...@@ -1597,21 +1983,21 @@ final class DualPivotQuicksort { ...@@ -1597,21 +1983,21 @@ final class DualPivotQuicksort {
* Phase 1: Move NaNs to the end of the array. * Phase 1: Move NaNs to the end of the array.
*/ */
while (left <= right && Float.isNaN(a[right])) { while (left <= right && Float.isNaN(a[right])) {
right--; --right;
} }
for (int k = right; --k >= left; ) { for (int k = right; --k >= left; ) {
float ak = a[k]; float ak = a[k];
if (ak != ak) { // a[k] is NaN if (ak != ak) { // a[k] is NaN
a[k] = a[right]; a[k] = a[right];
a[right] = ak; a[right] = ak;
right--; --right;
} }
} }
/* /*
* Phase 2: Sort everything except NaNs (which are already in place). * Phase 2: Sort everything except NaNs (which are already in place).
*/ */
sort(a, left, right, true); doSort(a, left, right);
/* /*
* Phase 3: Place negative zeros before positive zeros. * Phase 3: Place negative zeros before positive zeros.
...@@ -1636,7 +2022,7 @@ final class DualPivotQuicksort { ...@@ -1636,7 +2022,7 @@ final class DualPivotQuicksort {
* Skip the last negative value (if any) or all leading negative zeros. * Skip the last negative value (if any) or all leading negative zeros.
*/ */
while (left <= right && Float.floatToRawIntBits(a[left]) < 0) { while (left <= right && Float.floatToRawIntBits(a[left]) < 0) {
left++; ++left;
} }
/* /*
...@@ -1672,6 +2058,99 @@ final class DualPivotQuicksort { ...@@ -1672,6 +2058,99 @@ final class DualPivotQuicksort {
} }
} }
/**
* Sorts the specified range of the array.
*
* @param a the array to be sorted
* @param left the index of the first element, inclusive, to be sorted
* @param right the index of the last element, inclusive, to be sorted
*/
private static void doSort(float[] a, int left, int right) {
// Use Quicksort on small arrays
if (right - left < QUICKSORT_THRESHOLD) {
sort(a, left, right, true);
return;
}
/*
* Index run[i] is the start of i-th run
* (ascending or descending sequence).
*/
int[] run = new int[MAX_RUN_COUNT];
int count = 0; run[0] = left;
// Check if the array is nearly sorted
for (int k = left; k < right; run[count] = k) {
if (a[k] < a[k + 1]) { // ascending
while (++k <= right && a[k - 1] <= a[k]);
} else if (a[k] > a[k + 1]) { // descending
while (++k <= right && a[k - 1] >= a[k]);
for (int lo = run[count] - 1, hi = k; ++lo < --hi; ) {
float t = a[lo]; a[lo] = a[hi]; a[hi] = t;
}
} else { // equal
for (int m = MAX_RUN_LENGTH; ++k <= right && a[k - 1] == a[k]; ) {
if (--m == 0) {
sort(a, left, right, true);
return;
}
}
}
/*
* The array is not highly structured,
* use Quicksort instead of merge sort.
*/
if (++count == MAX_RUN_COUNT) {
sort(a, left, right, true);
return;
}
}
// Check special cases
if (run[count] == right++) { // The last run contains one element
run[++count] = right;
} else if (count == 1) { // The array is already sorted
return;
}
/*
* Create temporary array, which is used for merging.
* Implementation note: variable "right" is increased by 1.
*/
float[] b; byte odd = 0;
for (int n = 1; (n <<= 1) < count; odd ^= 1);
if (odd == 0) {
b = a; a = new float[b.length];
for (int i = left - 1; ++i < right; a[i] = b[i]);
} else {
b = new float[a.length];
}
// Merging
for (int last; count > 1; count = last) {
for (int k = (last = 0) + 2; k <= count; k += 2) {
int hi = run[k], mi = run[k - 1];
for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) {
if (q >= hi || p < mi && a[p] <= a[q]) {
b[i] = a[p++];
} else {
b[i] = a[q++];
}
}
run[++last] = hi;
}
if ((count & 1) != 0) {
for (int i = right, lo = run[count - 1]; --i >= lo;
b[i] = a[i]
);
run[++last] = right;
}
float[] t = a; a = b; b = t;
}
}
/** /**
* Sorts the specified range of the array by Dual-Pivot Quicksort. * Sorts the specified range of the array by Dual-Pivot Quicksort.
* *
...@@ -1680,10 +2159,10 @@ final class DualPivotQuicksort { ...@@ -1680,10 +2159,10 @@ final class DualPivotQuicksort {
* @param right the index of the last element, inclusive, to be sorted * @param right the index of the last element, inclusive, to be sorted
* @param leftmost indicates if this part is the leftmost in the range * @param leftmost indicates if this part is the leftmost in the range
*/ */
private static void sort(float[] a, int left, int right,boolean leftmost) { private static void sort(float[] a, int left, int right, boolean leftmost) {
int length = right - left + 1; int length = right - left + 1;
// Use insertion sort on small arrays // Use insertion sort on tiny arrays
if (length < INSERTION_SORT_THRESHOLD) { if (length < INSERTION_SORT_THRESHOLD) {
if (leftmost) { if (leftmost) {
/* /*
...@@ -1706,26 +2185,24 @@ final class DualPivotQuicksort { ...@@ -1706,26 +2185,24 @@ final class DualPivotQuicksort {
* Skip the longest ascending sequence. * Skip the longest ascending sequence.
*/ */
do { do {
if (left++ >= right) { if (left >= right) {
return; return;
} }
} while (a[left - 1] <= a[left]); } while (a[++left] >= a[left - 1]);
/* /*
* Every element from adjoining part plays the role * Every element from adjoining part plays the role
* of sentinel, therefore this allows us to avoid the * of sentinel, therefore this allows us to avoid the
* left range check on each iteration. Moreover, we use * left range check on each iteration. Moreover, we use
* the best improved algorithm, so called pair insertion * the more optimized algorithm, so called pair insertion
* sort, which is faster than traditional implementation * sort, which is faster (in the context of Quicksort)
* in the context of Dual-Pivot Quicksort. * than traditional implementation of insertion sort.
*/ */
for (int k = left--; (left += 2) <= right; ) { for (int k = left; ++left <= right; k = ++left) {
float a1, a2; k = left - 1; float a1 = a[k], a2 = a[left];
if (a[k] < a[left]) { if (a1 < a2) {
a2 = a[k]; a1 = a[left]; a2 = a1; a1 = a[left];
} else {
a1 = a[k]; a2 = a[left];
} }
while (a1 < a[--k]) { while (a1 < a[--k]) {
a[k + 2] = a[k]; a[k + 2] = a[k];
...@@ -1782,6 +2259,11 @@ final class DualPivotQuicksort { ...@@ -1782,6 +2259,11 @@ final class DualPivotQuicksort {
} }
} }
// Pointers
int less = left; // The index of the first element of center part
int great = right; // The index before the first element of right part
if (a[e1] != a[e2] && a[e2] != a[e3] && a[e3] != a[e4] && a[e4] != a[e5]) {
/* /*
* Use the second and fourth of the five sorted elements as pivots. * Use the second and fourth of the five sorted elements as pivots.
* These values are inexpensive approximations of the first and * These values are inexpensive approximations of the first and
...@@ -1790,11 +2272,6 @@ final class DualPivotQuicksort { ...@@ -1790,11 +2272,6 @@ final class DualPivotQuicksort {
float pivot1 = a[e2]; float pivot1 = a[e2];
float pivot2 = a[e4]; float pivot2 = a[e4];
// Pointers
int less = left; // The index of the first element of center part
int great = right; // The index before the first element of right part
if (pivot1 != pivot2) {
/* /*
* The first and the last elements to be sorted are moved to the * The first and the last elements to be sorted are moved to the
* locations formerly occupied by the pivots. When partitioning * locations formerly occupied by the pivots. When partitioning
...@@ -1839,7 +2316,7 @@ final class DualPivotQuicksort { ...@@ -1839,7 +2316,7 @@ final class DualPivotQuicksort {
* of "a[i++] = b;" due to performance issue. * of "a[i++] = b;" due to performance issue.
*/ */
a[less] = ak; a[less] = ak;
less++; ++less;
} else if (ak > pivot2) { // Move a[k] to right part } else if (ak > pivot2) { // Move a[k] to right part
while (a[great] > pivot2) { while (a[great] > pivot2) {
if (great-- == k) { if (great-- == k) {
...@@ -1849,7 +2326,7 @@ final class DualPivotQuicksort { ...@@ -1849,7 +2326,7 @@ final class DualPivotQuicksort {
if (a[great] < pivot1) { // a[great] <= pivot2 if (a[great] < pivot1) { // a[great] <= pivot2
a[k] = a[less]; a[k] = a[less];
a[less] = a[great]; a[less] = a[great];
less++; ++less;
} else { // pivot1 <= a[great] <= pivot2 } else { // pivot1 <= a[great] <= pivot2
a[k] = a[great]; a[k] = a[great];
} }
...@@ -1858,7 +2335,7 @@ final class DualPivotQuicksort { ...@@ -1858,7 +2335,7 @@ final class DualPivotQuicksort {
* of "a[i--] = b;" due to performance issue. * of "a[i--] = b;" due to performance issue.
*/ */
a[great] = ak; a[great] = ak;
great--; --great;
} }
} }
...@@ -1879,10 +2356,11 @@ final class DualPivotQuicksort { ...@@ -1879,10 +2356,11 @@ final class DualPivotQuicksort {
* Skip elements, which are equal to pivot values. * Skip elements, which are equal to pivot values.
*/ */
while (a[less] == pivot1) { while (a[less] == pivot1) {
less++; ++less;
} }
while (a[great] == pivot2) { while (a[great] == pivot2) {
great--; --great;
} }
/* /*
...@@ -1910,7 +2388,7 @@ final class DualPivotQuicksort { ...@@ -1910,7 +2388,7 @@ final class DualPivotQuicksort {
if (ak == pivot1) { // Move a[k] to left part if (ak == pivot1) { // Move a[k] to left part
a[k] = a[less]; a[k] = a[less];
a[less] = ak; a[less] = ak;
less++; ++less;
} else if (ak == pivot2) { // Move a[k] to right part } else if (ak == pivot2) { // Move a[k] to right part
while (a[great] == pivot2) { while (a[great] == pivot2) {
if (great-- == k) { if (great-- == k) {
...@@ -1928,12 +2406,12 @@ final class DualPivotQuicksort { ...@@ -1928,12 +2406,12 @@ final class DualPivotQuicksort {
* accurate assignment a[less] = a[great]. * accurate assignment a[less] = a[great].
*/ */
a[less] = a[great]; a[less] = a[great];
less++; ++less;
} else { // pivot1 < a[great] < pivot2 } else { // pivot1 < a[great] < pivot2
a[k] = a[great]; a[k] = a[great];
} }
a[great] = ak; a[great] = ak;
great--; --great;
} }
} }
} }
...@@ -1941,7 +2419,13 @@ final class DualPivotQuicksort { ...@@ -1941,7 +2419,13 @@ final class DualPivotQuicksort {
// Sort center part recursively // Sort center part recursively
sort(a, less, great, false); sort(a, less, great, false);
} else { // Pivots are equal } else { // Partitioning with one pivot
/*
* Use the third of the five sorted elements as pivot.
* This value is inexpensive approximation of the median.
*/
float pivot = a[e3];
/* /*
* Partitioning degenerates to the traditional 3-way * Partitioning degenerates to the traditional 3-way
* (or "Dutch National Flag") schema: * (or "Dutch National Flag") schema:
...@@ -1963,27 +2447,27 @@ final class DualPivotQuicksort { ...@@ -1963,27 +2447,27 @@ final class DualPivotQuicksort {
* Pointer k is the first index of ?-part. * Pointer k is the first index of ?-part.
*/ */
for (int k = less; k <= great; ++k) { for (int k = less; k <= great; ++k) {
if (a[k] == pivot1) { if (a[k] == pivot) {
continue; continue;
} }
float ak = a[k]; float ak = a[k];
if (ak < pivot1) { // Move a[k] to left part if (ak < pivot) { // Move a[k] to left part
a[k] = a[less]; a[k] = a[less];
a[less] = ak; a[less] = ak;
less++; ++less;
} else { // a[k] > pivot1 - Move a[k] to right part } else { // a[k] > pivot - Move a[k] to right part
while (a[great] > pivot1) { while (a[great] > pivot) {
great--; --great;
} }
if (a[great] < pivot1) { // a[great] <= pivot1 if (a[great] < pivot) { // a[great] <= pivot
a[k] = a[less]; a[k] = a[less];
a[less] = a[great]; a[less] = a[great];
less++; ++less;
} else { // a[great] == pivot1 } else { // a[great] == pivot
/* /*
* Even though a[great] equals to pivot1, the * Even though a[great] equals to pivot, the
* assignment a[k] = pivot1 may be incorrect, * assignment a[k] = pivot may be incorrect,
* if a[great] and pivot1 are floating-point * if a[great] and pivot are floating-point
* zeros of different signs. Therefore in float * zeros of different signs. Therefore in float
* and double sorting methods we have to use * and double sorting methods we have to use
* more accurate assignment a[k] = a[great]. * more accurate assignment a[k] = a[great].
...@@ -1991,7 +2475,7 @@ final class DualPivotQuicksort { ...@@ -1991,7 +2475,7 @@ final class DualPivotQuicksort {
a[k] = a[great]; a[k] = a[great];
} }
a[great] = ak; a[great] = ak;
great--; --great;
} }
} }
...@@ -2026,21 +2510,21 @@ final class DualPivotQuicksort { ...@@ -2026,21 +2510,21 @@ final class DualPivotQuicksort {
* Phase 1: Move NaNs to the end of the array. * Phase 1: Move NaNs to the end of the array.
*/ */
while (left <= right && Double.isNaN(a[right])) { while (left <= right && Double.isNaN(a[right])) {
right--; --right;
} }
for (int k = right; --k >= left; ) { for (int k = right; --k >= left; ) {
double ak = a[k]; double ak = a[k];
if (ak != ak) { // a[k] is NaN if (ak != ak) { // a[k] is NaN
a[k] = a[right]; a[k] = a[right];
a[right] = ak; a[right] = ak;
right--; --right;
} }
} }
/* /*
* Phase 2: Sort everything except NaNs (which are already in place). * Phase 2: Sort everything except NaNs (which are already in place).
*/ */
sort(a, left, right, true); doSort(a, left, right);
/* /*
* Phase 3: Place negative zeros before positive zeros. * Phase 3: Place negative zeros before positive zeros.
...@@ -2065,7 +2549,7 @@ final class DualPivotQuicksort { ...@@ -2065,7 +2549,7 @@ final class DualPivotQuicksort {
* Skip the last negative value (if any) or all leading negative zeros. * Skip the last negative value (if any) or all leading negative zeros.
*/ */
while (left <= right && Double.doubleToRawLongBits(a[left]) < 0) { while (left <= right && Double.doubleToRawLongBits(a[left]) < 0) {
left++; ++left;
} }
/* /*
...@@ -2101,6 +2585,99 @@ final class DualPivotQuicksort { ...@@ -2101,6 +2585,99 @@ final class DualPivotQuicksort {
} }
} }
/**
* Sorts the specified range of the array.
*
* @param a the array to be sorted
* @param left the index of the first element, inclusive, to be sorted
* @param right the index of the last element, inclusive, to be sorted
*/
private static void doSort(double[] a, int left, int right) {
// Use Quicksort on small arrays
if (right - left < QUICKSORT_THRESHOLD) {
sort(a, left, right, true);
return;
}
/*
* Index run[i] is the start of i-th run
* (ascending or descending sequence).
*/
int[] run = new int[MAX_RUN_COUNT];
int count = 0; run[0] = left;
// Check if the array is nearly sorted
for (int k = left; k < right; run[count] = k) {
if (a[k] < a[k + 1]) { // ascending
while (++k <= right && a[k - 1] <= a[k]);
} else if (a[k] > a[k + 1]) { // descending
while (++k <= right && a[k - 1] >= a[k]);
for (int lo = run[count] - 1, hi = k; ++lo < --hi; ) {
double t = a[lo]; a[lo] = a[hi]; a[hi] = t;
}
} else { // equal
for (int m = MAX_RUN_LENGTH; ++k <= right && a[k - 1] == a[k]; ) {
if (--m == 0) {
sort(a, left, right, true);
return;
}
}
}
/*
* The array is not highly structured,
* use Quicksort instead of merge sort.
*/
if (++count == MAX_RUN_COUNT) {
sort(a, left, right, true);
return;
}
}
// Check special cases
if (run[count] == right++) { // The last run contains one element
run[++count] = right;
} else if (count == 1) { // The array is already sorted
return;
}
/*
* Create temporary array, which is used for merging.
* Implementation note: variable "right" is increased by 1.
*/
double[] b; byte odd = 0;
for (int n = 1; (n <<= 1) < count; odd ^= 1);
if (odd == 0) {
b = a; a = new double[b.length];
for (int i = left - 1; ++i < right; a[i] = b[i]);
} else {
b = new double[a.length];
}
// Merging
for (int last; count > 1; count = last) {
for (int k = (last = 0) + 2; k <= count; k += 2) {
int hi = run[k], mi = run[k - 1];
for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) {
if (q >= hi || p < mi && a[p] <= a[q]) {
b[i] = a[p++];
} else {
b[i] = a[q++];
}
}
run[++last] = hi;
}
if ((count & 1) != 0) {
for (int i = right, lo = run[count - 1]; --i >= lo;
b[i] = a[i]
);
run[++last] = right;
}
double[] t = a; a = b; b = t;
}
}
/** /**
* Sorts the specified range of the array by Dual-Pivot Quicksort. * Sorts the specified range of the array by Dual-Pivot Quicksort.
* *
...@@ -2109,10 +2686,10 @@ final class DualPivotQuicksort { ...@@ -2109,10 +2686,10 @@ final class DualPivotQuicksort {
* @param right the index of the last element, inclusive, to be sorted * @param right the index of the last element, inclusive, to be sorted
* @param leftmost indicates if this part is the leftmost in the range * @param leftmost indicates if this part is the leftmost in the range
*/ */
private static void sort(double[] a, int left,int right,boolean leftmost) { private static void sort(double[] a, int left, int right, boolean leftmost) {
int length = right - left + 1; int length = right - left + 1;
// Use insertion sort on small arrays // Use insertion sort on tiny arrays
if (length < INSERTION_SORT_THRESHOLD) { if (length < INSERTION_SORT_THRESHOLD) {
if (leftmost) { if (leftmost) {
/* /*
...@@ -2135,26 +2712,24 @@ final class DualPivotQuicksort { ...@@ -2135,26 +2712,24 @@ final class DualPivotQuicksort {
* Skip the longest ascending sequence. * Skip the longest ascending sequence.
*/ */
do { do {
if (left++ >= right) { if (left >= right) {
return; return;
} }
} while (a[left - 1] <= a[left]); } while (a[++left] >= a[left - 1]);
/* /*
* Every element from adjoining part plays the role * Every element from adjoining part plays the role
* of sentinel, therefore this allows us to avoid the * of sentinel, therefore this allows us to avoid the
* left range check on each iteration. Moreover, we use * left range check on each iteration. Moreover, we use
* the best improved algorithm, so called pair insertion * the more optimized algorithm, so called pair insertion
* sort, which is faster than traditional implementation * sort, which is faster (in the context of Quicksort)
* in the context of Dual-Pivot Quicksort. * than traditional implementation of insertion sort.
*/ */
for (int k = left--; (left += 2) <= right; ) { for (int k = left; ++left <= right; k = ++left) {
double a1, a2; k = left - 1; double a1 = a[k], a2 = a[left];
if (a[k] < a[left]) { if (a1 < a2) {
a2 = a[k]; a1 = a[left]; a2 = a1; a1 = a[left];
} else {
a1 = a[k]; a2 = a[left];
} }
while (a1 < a[--k]) { while (a1 < a[--k]) {
a[k + 2] = a[k]; a[k + 2] = a[k];
...@@ -2211,6 +2786,11 @@ final class DualPivotQuicksort { ...@@ -2211,6 +2786,11 @@ final class DualPivotQuicksort {
} }
} }
// Pointers
int less = left; // The index of the first element of center part
int great = right; // The index before the first element of right part
if (a[e1] != a[e2] && a[e2] != a[e3] && a[e3] != a[e4] && a[e4] != a[e5]) {
/* /*
* Use the second and fourth of the five sorted elements as pivots. * Use the second and fourth of the five sorted elements as pivots.
* These values are inexpensive approximations of the first and * These values are inexpensive approximations of the first and
...@@ -2219,11 +2799,6 @@ final class DualPivotQuicksort { ...@@ -2219,11 +2799,6 @@ final class DualPivotQuicksort {
double pivot1 = a[e2]; double pivot1 = a[e2];
double pivot2 = a[e4]; double pivot2 = a[e4];
// Pointers
int less = left; // The index of the first element of center part
int great = right; // The index before the first element of right part
if (pivot1 != pivot2) {
/* /*
* The first and the last elements to be sorted are moved to the * The first and the last elements to be sorted are moved to the
* locations formerly occupied by the pivots. When partitioning * locations formerly occupied by the pivots. When partitioning
...@@ -2268,7 +2843,7 @@ final class DualPivotQuicksort { ...@@ -2268,7 +2843,7 @@ final class DualPivotQuicksort {
* of "a[i++] = b;" due to performance issue. * of "a[i++] = b;" due to performance issue.
*/ */
a[less] = ak; a[less] = ak;
less++; ++less;
} else if (ak > pivot2) { // Move a[k] to right part } else if (ak > pivot2) { // Move a[k] to right part
while (a[great] > pivot2) { while (a[great] > pivot2) {
if (great-- == k) { if (great-- == k) {
...@@ -2278,7 +2853,7 @@ final class DualPivotQuicksort { ...@@ -2278,7 +2853,7 @@ final class DualPivotQuicksort {
if (a[great] < pivot1) { // a[great] <= pivot2 if (a[great] < pivot1) { // a[great] <= pivot2
a[k] = a[less]; a[k] = a[less];
a[less] = a[great]; a[less] = a[great];
less++; ++less;
} else { // pivot1 <= a[great] <= pivot2 } else { // pivot1 <= a[great] <= pivot2
a[k] = a[great]; a[k] = a[great];
} }
...@@ -2287,7 +2862,7 @@ final class DualPivotQuicksort { ...@@ -2287,7 +2862,7 @@ final class DualPivotQuicksort {
* of "a[i--] = b;" due to performance issue. * of "a[i--] = b;" due to performance issue.
*/ */
a[great] = ak; a[great] = ak;
great--; --great;
} }
} }
...@@ -2308,10 +2883,11 @@ final class DualPivotQuicksort { ...@@ -2308,10 +2883,11 @@ final class DualPivotQuicksort {
* Skip elements, which are equal to pivot values. * Skip elements, which are equal to pivot values.
*/ */
while (a[less] == pivot1) { while (a[less] == pivot1) {
less++; ++less;
} }
while (a[great] == pivot2) { while (a[great] == pivot2) {
great--; --great;
} }
/* /*
...@@ -2339,7 +2915,7 @@ final class DualPivotQuicksort { ...@@ -2339,7 +2915,7 @@ final class DualPivotQuicksort {
if (ak == pivot1) { // Move a[k] to left part if (ak == pivot1) { // Move a[k] to left part
a[k] = a[less]; a[k] = a[less];
a[less] = ak; a[less] = ak;
less++; ++less;
} else if (ak == pivot2) { // Move a[k] to right part } else if (ak == pivot2) { // Move a[k] to right part
while (a[great] == pivot2) { while (a[great] == pivot2) {
if (great-- == k) { if (great-- == k) {
...@@ -2357,12 +2933,12 @@ final class DualPivotQuicksort { ...@@ -2357,12 +2933,12 @@ final class DualPivotQuicksort {
* accurate assignment a[less] = a[great]. * accurate assignment a[less] = a[great].
*/ */
a[less] = a[great]; a[less] = a[great];
less++; ++less;
} else { // pivot1 < a[great] < pivot2 } else { // pivot1 < a[great] < pivot2
a[k] = a[great]; a[k] = a[great];
} }
a[great] = ak; a[great] = ak;
great--; --great;
} }
} }
} }
...@@ -2370,7 +2946,13 @@ final class DualPivotQuicksort { ...@@ -2370,7 +2946,13 @@ final class DualPivotQuicksort {
// Sort center part recursively // Sort center part recursively
sort(a, less, great, false); sort(a, less, great, false);
} else { // Pivots are equal } else { // Partitioning with one pivot
/*
* Use the third of the five sorted elements as pivot.
* This value is inexpensive approximation of the median.
*/
double pivot = a[e3];
/* /*
* Partitioning degenerates to the traditional 3-way * Partitioning degenerates to the traditional 3-way
* (or "Dutch National Flag") schema: * (or "Dutch National Flag") schema:
...@@ -2392,27 +2974,27 @@ final class DualPivotQuicksort { ...@@ -2392,27 +2974,27 @@ final class DualPivotQuicksort {
* Pointer k is the first index of ?-part. * Pointer k is the first index of ?-part.
*/ */
for (int k = less; k <= great; ++k) { for (int k = less; k <= great; ++k) {
if (a[k] == pivot1) { if (a[k] == pivot) {
continue; continue;
} }
double ak = a[k]; double ak = a[k];
if (ak < pivot1) { // Move a[k] to left part if (ak < pivot) { // Move a[k] to left part
a[k] = a[less]; a[k] = a[less];
a[less] = ak; a[less] = ak;
less++; ++less;
} else { // a[k] > pivot1 - Move a[k] to right part } else { // a[k] > pivot - Move a[k] to right part
while (a[great] > pivot1) { while (a[great] > pivot) {
great--; --great;
} }
if (a[great] < pivot1) { // a[great] <= pivot1 if (a[great] < pivot) { // a[great] <= pivot
a[k] = a[less]; a[k] = a[less];
a[less] = a[great]; a[less] = a[great];
less++; ++less;
} else { // a[great] == pivot1 } else { // a[great] == pivot
/* /*
* Even though a[great] equals to pivot1, the * Even though a[great] equals to pivot, the
* assignment a[k] = pivot1 may be incorrect, * assignment a[k] = pivot may be incorrect,
* if a[great] and pivot1 are floating-point * if a[great] and pivot are floating-point
* zeros of different signs. Therefore in float * zeros of different signs. Therefore in float
* and double sorting methods we have to use * and double sorting methods we have to use
* more accurate assignment a[k] = a[great]. * more accurate assignment a[k] = a[great].
...@@ -2420,7 +3002,7 @@ final class DualPivotQuicksort { ...@@ -2420,7 +3002,7 @@ final class DualPivotQuicksort {
a[k] = a[great]; a[k] = a[great];
} }
a[great] = ak; a[great] = ak;
great--; --great;
} }
} }
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
/* /*
* @test * @test
* @bug 6880672 6896573 6899694 6976036 * @bug 6880672 6896573 6899694 6976036 7013585
* @summary Exercise Arrays.sort * @summary Exercise Arrays.sort
* @build Sorting * @build Sorting
* @run main Sorting -shortrun * @run main Sorting -shortrun
...@@ -546,13 +546,19 @@ public class Sorting { ...@@ -546,13 +546,19 @@ public class Sorting {
private static void prepareSubArray(int[] a, int fromIndex, int toIndex, int m) { private static void prepareSubArray(int[] a, int fromIndex, int toIndex, int m) {
for (int i = 0; i < fromIndex; i++) { for (int i = 0; i < fromIndex; i++) {
a[i] = 0xBABA; a[i] = 0xDEDA;
}
int middle = (fromIndex + toIndex) >>> 1;
int k = 0;
for (int i = fromIndex; i < middle; i++) {
a[i] = k++;
} }
for (int i = fromIndex; i < toIndex; i++) { for (int i = middle; i < toIndex; i++) {
a[i] = -i + m; a[i] = k--;
} }
for (int i = toIndex; i < a.length; i++) { for (int i = toIndex; i < a.length; i++) {
a[i] = 0xDEDA; a[i] = 0xBABA;
} }
} }
...@@ -1518,9 +1524,9 @@ public class Sorting { ...@@ -1518,9 +1524,9 @@ public class Sorting {
private static void checkSubArray(Integer[] a, int fromIndex, int toIndex, int m) { private static void checkSubArray(Integer[] a, int fromIndex, int toIndex, int m) {
for (int i = 0; i < fromIndex; i++) { for (int i = 0; i < fromIndex; i++) {
if (a[i].intValue() != 0xBABA) { if (a[i].intValue() != 0xDEDA) {
failed("Range sort changes left element on position " + i + failed("Range sort changes left element on position " + i +
": " + a[i] + ", must be " + 0xBABA); ": " + a[i] + ", must be " + 0xDEDA);
} }
} }
...@@ -1531,18 +1537,18 @@ public class Sorting { ...@@ -1531,18 +1537,18 @@ public class Sorting {
} }
for (int i = toIndex; i < a.length; i++) { for (int i = toIndex; i < a.length; i++) {
if (a[i].intValue() != 0xDEDA) { if (a[i].intValue() != 0xBABA) {
failed("Range sort changes right element on position " + i + failed("Range sort changes right element on position " + i +
": " + a[i] + ", must be " + 0xDEDA); ": " + a[i] + ", must be " + 0xBABA);
} }
} }
} }
private static void checkSubArray(int[] a, int fromIndex, int toIndex, int m) { private static void checkSubArray(int[] a, int fromIndex, int toIndex, int m) {
for (int i = 0; i < fromIndex; i++) { for (int i = 0; i < fromIndex; i++) {
if (a[i] != 0xBABA) { if (a[i] != 0xDEDA) {
failed("Range sort changes left element on position " + i + failed("Range sort changes left element on position " + i +
": " + a[i] + ", must be " + 0xBABA); ": " + a[i] + ", must be " + 0xDEDA);
} }
} }
...@@ -1553,18 +1559,18 @@ public class Sorting { ...@@ -1553,18 +1559,18 @@ public class Sorting {
} }
for (int i = toIndex; i < a.length; i++) { for (int i = toIndex; i < a.length; i++) {
if (a[i] != 0xDEDA) { if (a[i] != 0xBABA) {
failed("Range sort changes right element on position " + i + failed("Range sort changes right element on position " + i +
": " + a[i] + ", must be " + 0xDEDA); ": " + a[i] + ", must be " + 0xBABA);
} }
} }
} }
private static void checkSubArray(byte[] a, int fromIndex, int toIndex, int m) { private static void checkSubArray(byte[] a, int fromIndex, int toIndex, int m) {
for (int i = 0; i < fromIndex; i++) { for (int i = 0; i < fromIndex; i++) {
if (a[i] != (byte) 0xBABA) { if (a[i] != (byte) 0xDEDA) {
failed("Range sort changes left element on position " + i + failed("Range sort changes left element on position " + i +
": " + a[i] + ", must be " + 0xBABA); ": " + a[i] + ", must be " + 0xDEDA);
} }
} }
...@@ -1575,18 +1581,18 @@ public class Sorting { ...@@ -1575,18 +1581,18 @@ public class Sorting {
} }
for (int i = toIndex; i < a.length; i++) { for (int i = toIndex; i < a.length; i++) {
if (a[i] != (byte) 0xDEDA) { if (a[i] != (byte) 0xBABA) {
failed("Range sort changes right element on position " + i + failed("Range sort changes right element on position " + i +
": " + a[i] + ", must be " + 0xDEDA); ": " + a[i] + ", must be " + 0xBABA);
} }
} }
} }
private static void checkSubArray(long[] a, int fromIndex, int toIndex, int m) { private static void checkSubArray(long[] a, int fromIndex, int toIndex, int m) {
for (int i = 0; i < fromIndex; i++) { for (int i = 0; i < fromIndex; i++) {
if (a[i] != (long) 0xBABA) { if (a[i] != (long) 0xDEDA) {
failed("Range sort changes left element on position " + i + failed("Range sort changes left element on position " + i +
": " + a[i] + ", must be " + 0xBABA); ": " + a[i] + ", must be " + 0xDEDA);
} }
} }
...@@ -1597,18 +1603,18 @@ public class Sorting { ...@@ -1597,18 +1603,18 @@ public class Sorting {
} }
for (int i = toIndex; i < a.length; i++) { for (int i = toIndex; i < a.length; i++) {
if (a[i] != (long) 0xDEDA) { if (a[i] != (long) 0xBABA) {
failed("Range sort changes right element on position " + i + failed("Range sort changes right element on position " + i +
": " + a[i] + ", must be " + 0xDEDA); ": " + a[i] + ", must be " + 0xBABA);
} }
} }
} }
private static void checkSubArray(char[] a, int fromIndex, int toIndex, int m) { private static void checkSubArray(char[] a, int fromIndex, int toIndex, int m) {
for (int i = 0; i < fromIndex; i++) { for (int i = 0; i < fromIndex; i++) {
if (a[i] != (char) 0xBABA) { if (a[i] != (char) 0xDEDA) {
failed("Range sort changes left element on position " + i + failed("Range sort changes left element on position " + i +
": " + a[i] + ", must be " + 0xBABA); ": " + a[i] + ", must be " + 0xDEDA);
} }
} }
...@@ -1619,18 +1625,18 @@ public class Sorting { ...@@ -1619,18 +1625,18 @@ public class Sorting {
} }
for (int i = toIndex; i < a.length; i++) { for (int i = toIndex; i < a.length; i++) {
if (a[i] != (char) 0xDEDA) { if (a[i] != (char) 0xBABA) {
failed("Range sort changes right element on position " + i + failed("Range sort changes right element on position " + i +
": " + a[i] + ", must be " + 0xDEDA); ": " + a[i] + ", must be " + 0xBABA);
} }
} }
} }
private static void checkSubArray(short[] a, int fromIndex, int toIndex, int m) { private static void checkSubArray(short[] a, int fromIndex, int toIndex, int m) {
for (int i = 0; i < fromIndex; i++) { for (int i = 0; i < fromIndex; i++) {
if (a[i] != (short) 0xBABA) { if (a[i] != (short) 0xDEDA) {
failed("Range sort changes left element on position " + i + failed("Range sort changes left element on position " + i +
": " + a[i] + ", must be " + 0xBABA); ": " + a[i] + ", must be " + 0xDEDA);
} }
} }
...@@ -1641,18 +1647,18 @@ public class Sorting { ...@@ -1641,18 +1647,18 @@ public class Sorting {
} }
for (int i = toIndex; i < a.length; i++) { for (int i = toIndex; i < a.length; i++) {
if (a[i] != (short) 0xDEDA) { if (a[i] != (short) 0xBABA) {
failed("Range sort changes right element on position " + i + failed("Range sort changes right element on position " + i +
": " + a[i] + ", must be " + 0xDEDA); ": " + a[i] + ", must be " + 0xBABA);
} }
} }
} }
private static void checkSubArray(float[] a, int fromIndex, int toIndex, int m) { private static void checkSubArray(float[] a, int fromIndex, int toIndex, int m) {
for (int i = 0; i < fromIndex; i++) { for (int i = 0; i < fromIndex; i++) {
if (a[i] != (float) 0xBABA) { if (a[i] != (float) 0xDEDA) {
failed("Range sort changes left element on position " + i + failed("Range sort changes left element on position " + i +
": " + a[i] + ", must be " + 0xBABA); ": " + a[i] + ", must be " + 0xDEDA);
} }
} }
...@@ -1663,18 +1669,18 @@ public class Sorting { ...@@ -1663,18 +1669,18 @@ public class Sorting {
} }
for (int i = toIndex; i < a.length; i++) { for (int i = toIndex; i < a.length; i++) {
if (a[i] != (float) 0xDEDA) { if (a[i] != (float) 0xBABA) {
failed("Range sort changes right element on position " + i + failed("Range sort changes right element on position " + i +
": " + a[i] + ", must be " + 0xDEDA); ": " + a[i] + ", must be " + 0xBABA);
} }
} }
} }
private static void checkSubArray(double[] a, int fromIndex, int toIndex, int m) { private static void checkSubArray(double[] a, int fromIndex, int toIndex, int m) {
for (int i = 0; i < fromIndex; i++) { for (int i = 0; i < fromIndex; i++) {
if (a[i] != (double) 0xBABA) { if (a[i] != (double) 0xDEDA) {
failed("Range sort changes left element on position " + i + failed("Range sort changes left element on position " + i +
": " + a[i] + ", must be " + 0xBABA); ": " + a[i] + ", must be " + 0xDEDA);
} }
} }
...@@ -1685,9 +1691,9 @@ public class Sorting { ...@@ -1685,9 +1691,9 @@ public class Sorting {
} }
for (int i = toIndex; i < a.length; i++) { for (int i = toIndex; i < a.length; i++) {
if (a[i] != (double) 0xDEDA) { if (a[i] != (double) 0xBABA) {
failed("Range sort changes right element on position " + i + failed("Range sort changes right element on position " + i +
": " + a[i] + ", must be " + 0xDEDA); ": " + a[i] + ", must be " + 0xBABA);
} }
} }
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册