提交 090a9645 编写于 作者: A alanb

6976036: Dual-pivot quicksort update (10/2010 tune-up)

Reviewed-by: alanb
Contributed-by: vladimir.yaroslavskiy@oracle.com
上级 adff931e
...@@ -97,7 +97,8 @@ public class Arrays { ...@@ -97,7 +97,8 @@ public class Arrays {
* if {@code fromIndex < 0} or {@code toIndex > a.length} * if {@code fromIndex < 0} or {@code toIndex > a.length}
*/ */
public static void sort(int[] a, int fromIndex, int toIndex) { public static void sort(int[] a, int fromIndex, int toIndex) {
DualPivotQuicksort.sort(a, fromIndex, toIndex); rangeCheck(a.length, fromIndex, toIndex);
DualPivotQuicksort.sort(a, fromIndex, toIndex - 1);
} }
/** /**
...@@ -136,7 +137,8 @@ public class Arrays { ...@@ -136,7 +137,8 @@ public class Arrays {
* if {@code fromIndex < 0} or {@code toIndex > a.length} * if {@code fromIndex < 0} or {@code toIndex > a.length}
*/ */
public static void sort(long[] a, int fromIndex, int toIndex) { public static void sort(long[] a, int fromIndex, int toIndex) {
DualPivotQuicksort.sort(a, fromIndex, toIndex); rangeCheck(a.length, fromIndex, toIndex);
DualPivotQuicksort.sort(a, fromIndex, toIndex - 1);
} }
/** /**
...@@ -175,7 +177,8 @@ public class Arrays { ...@@ -175,7 +177,8 @@ public class Arrays {
* if {@code fromIndex < 0} or {@code toIndex > a.length} * if {@code fromIndex < 0} or {@code toIndex > a.length}
*/ */
public static void sort(short[] a, int fromIndex, int toIndex) { public static void sort(short[] a, int fromIndex, int toIndex) {
DualPivotQuicksort.sort(a, fromIndex, toIndex); rangeCheck(a.length, fromIndex, toIndex);
DualPivotQuicksort.sort(a, fromIndex, toIndex - 1);
} }
/** /**
...@@ -214,7 +217,8 @@ public class Arrays { ...@@ -214,7 +217,8 @@ public class Arrays {
* if {@code fromIndex < 0} or {@code toIndex > a.length} * if {@code fromIndex < 0} or {@code toIndex > a.length}
*/ */
public static void sort(char[] a, int fromIndex, int toIndex) { public static void sort(char[] a, int fromIndex, int toIndex) {
DualPivotQuicksort.sort(a, fromIndex, toIndex); rangeCheck(a.length, fromIndex, toIndex);
DualPivotQuicksort.sort(a, fromIndex, toIndex - 1);
} }
/** /**
...@@ -253,7 +257,8 @@ public class Arrays { ...@@ -253,7 +257,8 @@ public class Arrays {
* if {@code fromIndex < 0} or {@code toIndex > a.length} * if {@code fromIndex < 0} or {@code toIndex > a.length}
*/ */
public static void sort(byte[] a, int fromIndex, int toIndex) { public static void sort(byte[] a, int fromIndex, int toIndex) {
DualPivotQuicksort.sort(a, fromIndex, toIndex); rangeCheck(a.length, fromIndex, toIndex);
DualPivotQuicksort.sort(a, fromIndex, toIndex - 1);
} }
/** /**
...@@ -308,7 +313,8 @@ public class Arrays { ...@@ -308,7 +313,8 @@ public class Arrays {
* if {@code fromIndex < 0} or {@code toIndex > a.length} * if {@code fromIndex < 0} or {@code toIndex > a.length}
*/ */
public static void sort(float[] a, int fromIndex, int toIndex) { public static void sort(float[] a, int fromIndex, int toIndex) {
DualPivotQuicksort.sort(a, fromIndex, toIndex); rangeCheck(a.length, fromIndex, toIndex);
DualPivotQuicksort.sort(a, fromIndex, toIndex - 1);
} }
/** /**
...@@ -363,12 +369,12 @@ public class Arrays { ...@@ -363,12 +369,12 @@ public class Arrays {
* if {@code fromIndex < 0} or {@code toIndex > a.length} * if {@code fromIndex < 0} or {@code toIndex > a.length}
*/ */
public static void sort(double[] a, int fromIndex, int toIndex) { public static void sort(double[] a, int fromIndex, int toIndex) {
DualPivotQuicksort.sort(a, fromIndex, toIndex); rangeCheck(a.length, fromIndex, toIndex);
DualPivotQuicksort.sort(a, fromIndex, toIndex - 1);
} }
/* /*
* Sorting of complex type arrays. * Sorting of complex type arrays.
*
*/ */
/** /**
......
...@@ -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.06.21 m765.827.12i:5\7 * @version 2010.10.13 m765.827.12i:5\7p
* @since 1.7 * @since 1.7
*/ */
final class DualPivotQuicksort { final class DualPivotQuicksort {
...@@ -54,26 +54,26 @@ final class DualPivotQuicksort { ...@@ -54,26 +54,26 @@ final class DualPivotQuicksort {
* 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.
*/ */
private static final int INSERTION_SORT_THRESHOLD = 32; private static final int INSERTION_SORT_THRESHOLD = 47;
/** /**
* If the length of a byte array to be sorted is greater than * If the length of a byte array to be sorted is greater than this
* this constant, counting sort is used in preference to Quicksort. * constant, counting sort is used in preference to insertion sort.
*/ */
private static final int COUNTING_SORT_THRESHOLD_FOR_BYTE = 128; private static final int COUNTING_SORT_THRESHOLD_FOR_BYTE = 29;
/** /**
* If the length of a short or char array to be sorted is greater * If the length of a short or char array to be sorted is greater
* than this constant, counting sort is used in preference to Quicksort. * than this constant, counting sort is used in preference to Quicksort.
*/ */
private static final int COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR = 32768; private static final int COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR = 3200;
/* /*
* Sorting methods for seven primitive types. * Sorting methods for seven primitive types.
*/ */
/** /**
* Sorts the specified array into ascending numerical order. * Sorts the specified array.
* *
* @param a the array to be sorted * @param a the array to be sorted
*/ */
...@@ -82,58 +82,34 @@ final class DualPivotQuicksort { ...@@ -82,58 +82,34 @@ final class DualPivotQuicksort {
} }
/** /**
* Sorts the specified range of the array into ascending order. The range * Sorts the specified range of the array.
* to be sorted extends from the index {@code fromIndex}, inclusive, to
* the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
* the range to be sorted is empty (and the call is a no-op).
* *
* @param a the array to be sorted * @param a the array to be sorted
* @param fromIndex the index of the first element, inclusive, to be sorted * @param left the index of the first element, inclusive, to be sorted
* @param toIndex the index of the last element, exclusive, to be sorted * @param right the index of the last element, inclusive, to be sorted
* @throws IllegalArgumentException if {@code fromIndex > toIndex}
* @throws ArrayIndexOutOfBoundsException
* if {@code fromIndex < 0} or {@code toIndex > a.length}
*/ */
public static void sort(int[] a, int fromIndex, int toIndex) { public static void sort(int[] a, int left, int right) {
rangeCheck(a.length, fromIndex, toIndex); sort(a, left, right, true);
sort(a, fromIndex, toIndex - 1, true);
} }
/** /**
* Sorts the specified range of the array into ascending order by the * Sorts the specified range of the array by Dual-Pivot Quicksort.
* Dual-Pivot Quicksort algorithm. This method differs from the public
* {@code sort} method in that the {@code right} index is inclusive,
* it does no range checking on {@code left} or {@code right}, and has
* boolean flag whether insertion sort with sentinel is used or not.
* *
* @param a the array to be sorted * @param a the array to be sorted
* @param left the index of the first element, inclusive, 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 * @param right the index of the last element, inclusive, to be sorted
* @param leftmost indicates if the part is the most left in the range * @param leftmost indicates if this part is the leftmost in the range
*/ */
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 tiny arrays // Use insertion sort on small arrays
if (length < INSERTION_SORT_THRESHOLD) { if (length < INSERTION_SORT_THRESHOLD) {
if (!leftmost) { if (leftmost) {
/* /*
* Every element in adjoining part plays the role * Traditional (without sentinel) insertion sort,
* of sentinel, therefore this allows us to avoid * optimized for server VM, is used in case of
* the j >= left check on each iteration. * the leftmost part.
*/
for (int j, i = left + 1; i <= right; i++) {
int ai = a[i];
for (j = i - 1; ai < a[j]; j--) {
// assert j >= left;
a[j + 1] = a[j];
}
a[j + 1] = ai;
}
} else {
/*
* For case of leftmost part traditional (without a sentinel)
* insertion sort, optimized for server JVM, is used.
*/ */
for (int i = left, j = i; i < right; j = ++i) { for (int i = left, j = i; i < right; j = ++i) {
int ai = a[i + 1]; int ai = a[i + 1];
...@@ -145,12 +121,54 @@ final class DualPivotQuicksort { ...@@ -145,12 +121,54 @@ final class DualPivotQuicksort {
} }
a[j + 1] = ai; a[j + 1] = ai;
} }
} else {
/*
* Skip the longest ascending sequence.
*/
do {
if (left++ >= right) {
return;
}
} while (a[left - 1] <= a[left]);
/*
* Every element from adjoining part plays the role
* of sentinel, therefore this allows us to avoid the
* left range check on each iteration. Moreover, we use
* the best improved algorithm, so called pair insertion
* sort, which is faster than traditional implementation
* in the context of Dual-Pivot Quicksort.
*/
for (int k = left--; (left += 2) <= right; ) {
int a1, a2; k = left - 1;
if (a[k] < a[left]) {
a2 = a[k]; a1 = a[left];
} else {
a1 = a[k]; a2 = a[left];
}
while (a1 < a[--k]) {
a[k + 2] = a[k];
}
a[++k + 1] = a1;
while (a2 < a[--k]) {
a[k + 1] = a[k];
}
a[k + 1] = a2;
}
int last = a[right];
while (last < a[--right]) {
a[right + 1] = a[right];
}
a[right + 1] = last;
} }
return; return;
} }
// Inexpensive approximation of length / 7 // Inexpensive approximation of length / 7
int seventh = (length >>> 3) + (length >>> 6) + 1; int seventh = (length >> 3) + (length >> 6) + 1;
/* /*
* Sort five evenly spaced elements around (and including) the * Sort five evenly spaced elements around (and including) the
...@@ -232,10 +250,14 @@ final class DualPivotQuicksort { ...@@ -232,10 +250,14 @@ final class DualPivotQuicksort {
* Pointer k is the first index of ?-part. * Pointer k is the first index of ?-part.
*/ */
outer: outer:
for (int k = less; k <= great; k++) { for (int k = less - 1; ++k <= great; ) {
int ak = a[k]; int ak = a[k];
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];
/*
* Here and below we use "a[i] = b; i++;" instead
* 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
...@@ -244,13 +266,17 @@ final class DualPivotQuicksort { ...@@ -244,13 +266,17 @@ final class DualPivotQuicksort {
break outer; break outer;
} }
} }
if (a[great] < pivot1) { 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];
} }
/*
* Here and below we use "a[i] = b; i--;" instead
* of "a[i--] = b;" due to performance issue.
*/
a[great] = ak; a[great] = ak;
great--; great--;
} }
...@@ -265,7 +291,7 @@ final class DualPivotQuicksort { ...@@ -265,7 +291,7 @@ final class DualPivotQuicksort {
sort(a, great + 2, right, false); sort(a, great + 2, right, false);
/* /*
* If center part is too large (comprises > 5/7 of the array), * If center part is too large (comprises > 4/7 of the array),
* swap internal pivot values to ends. * swap internal pivot values to ends.
*/ */
if (less < e1 && e5 < great) { if (less < e1 && e5 < great) {
...@@ -299,7 +325,7 @@ final class DualPivotQuicksort { ...@@ -299,7 +325,7 @@ final class DualPivotQuicksort {
* Pointer k is the first index of ?-part. * Pointer k is the first index of ?-part.
*/ */
outer: outer:
for (int k = less; k <= great; k++) { for (int k = less - 1; ++k <= great; ) {
int ak = a[k]; int ak = a[k];
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];
...@@ -311,7 +337,7 @@ final class DualPivotQuicksort { ...@@ -311,7 +337,7 @@ final class DualPivotQuicksort {
break outer; break outer;
} }
} }
if (a[great] == pivot1) { if (a[great] == pivot1) { // a[great] < pivot2
a[k] = a[less]; a[k] = a[less];
/* /*
* Even though a[great] equals to pivot1, the * Even though a[great] equals to pivot1, the
...@@ -337,7 +363,7 @@ final class DualPivotQuicksort { ...@@ -337,7 +363,7 @@ final class DualPivotQuicksort {
} else { // Pivots are equal } else { // Pivots are equal
/* /*
* Partition degenerates to the traditional 3-way * Partitioning degenerates to the traditional 3-way
* (or "Dutch National Flag") schema: * (or "Dutch National Flag") schema:
* *
* left part center part right part * left part center part right part
...@@ -356,28 +382,20 @@ final class DualPivotQuicksort { ...@@ -356,28 +382,20 @@ final class DualPivotQuicksort {
* *
* Pointer k is the first index of ?-part. * Pointer k is the first index of ?-part.
*/ */
for (int k = left; k <= great; k++) { for (int k = less; k <= great; ++k) {
if (a[k] == pivot1) { if (a[k] == pivot1) {
continue; continue;
} }
int ak = a[k]; int ak = a[k];
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 { // a[k] > pivot1 - Move a[k] to right part } else { // a[k] > pivot1 - Move a[k] to right part
/*
* We know that pivot1 == a[e3] == pivot2. Thus, we know
* that great will still be >= k when the following loop
* terminates, even though we don't test for it explicitly.
* In other words, a[e3] acts as a sentinel for great.
*/
while (a[great] > pivot1) { while (a[great] > pivot1) {
// assert great > k;
great--; great--;
} }
if (a[great] < pivot1) { if (a[great] < pivot1) { // a[great] <= pivot1
a[k] = a[less]; a[k] = a[less];
a[less] = a[great]; a[less] = a[great];
less++; less++;
...@@ -397,14 +415,18 @@ final class DualPivotQuicksort { ...@@ -397,14 +415,18 @@ final class DualPivotQuicksort {
} }
} }
// Sort left and right parts recursively /*
* Sort left and right parts recursively.
* All elements from center part are equal
* and, therefore, already sorted.
*/
sort(a, left, less - 1, leftmost); sort(a, left, less - 1, leftmost);
sort(a, great + 1, right, false); sort(a, great + 1, right, false);
} }
} }
/** /**
* Sorts the specified array into ascending numerical order. * Sorts the specified array.
* *
* @param a the array to be sorted * @param a the array to be sorted
*/ */
...@@ -413,58 +435,34 @@ final class DualPivotQuicksort { ...@@ -413,58 +435,34 @@ final class DualPivotQuicksort {
} }
/** /**
* Sorts the specified range of the array into ascending order. The range * Sorts the specified range of the array.
* to be sorted extends from the index {@code fromIndex}, inclusive, to
* the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
* the range to be sorted is empty (and the call is a no-op).
* *
* @param a the array to be sorted * @param a the array to be sorted
* @param fromIndex the index of the first element, inclusive, to be sorted * @param left the index of the first element, inclusive, to be sorted
* @param toIndex the index of the last element, exclusive, to be sorted * @param right the index of the last element, inclusive, to be sorted
* @throws IllegalArgumentException if {@code fromIndex > toIndex}
* @throws ArrayIndexOutOfBoundsException
* if {@code fromIndex < 0} or {@code toIndex > a.length}
*/ */
public static void sort(long[] a, int fromIndex, int toIndex) { public static void sort(long[] a, int left, int right) {
rangeCheck(a.length, fromIndex, toIndex); sort(a, left, right, true);
sort(a, fromIndex, toIndex - 1, true);
} }
/** /**
* Sorts the specified range of the array into ascending order by the * Sorts the specified range of the array by Dual-Pivot Quicksort.
* Dual-Pivot Quicksort algorithm. This method differs from the public
* {@code sort} method in that the {@code right} index is inclusive,
* it does no range checking on {@code left} or {@code right}, and has
* boolean flag whether insertion sort with sentinel is used or not.
* *
* @param a the array to be sorted * @param a the array to be sorted
* @param left the index of the first element, inclusive, 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 * @param right the index of the last element, inclusive, to be sorted
* @param leftmost indicates if the part is the most left in the range * @param leftmost indicates if this part is the leftmost in the range
*/ */
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 tiny arrays // Use insertion sort on small arrays
if (length < INSERTION_SORT_THRESHOLD) { if (length < INSERTION_SORT_THRESHOLD) {
if (!leftmost) { if (leftmost) {
/*
* Every element in adjoining part plays the role
* of sentinel, therefore this allows us to avoid
* the j >= left check on each iteration.
*/
for (int j, i = left + 1; i <= right; i++) {
long ai = a[i];
for (j = i - 1; ai < a[j]; j--) {
// assert j >= left;
a[j + 1] = a[j];
}
a[j + 1] = ai;
}
} else {
/* /*
* For case of leftmost part traditional (without a sentinel) * Traditional (without sentinel) insertion sort,
* insertion sort, optimized for server JVM, is used. * optimized for server VM, is used in case of
* the leftmost part.
*/ */
for (int i = left, j = i; i < right; j = ++i) { for (int i = left, j = i; i < right; j = ++i) {
long ai = a[i + 1]; long ai = a[i + 1];
...@@ -476,381 +474,54 @@ final class DualPivotQuicksort { ...@@ -476,381 +474,54 @@ final class DualPivotQuicksort {
} }
a[j + 1] = ai; a[j + 1] = ai;
} }
} } else {
return;
}
// Inexpensive approximation of length / 7
int seventh = (length >>> 3) + (length >>> 6) + 1;
/*
* Sort five evenly spaced elements around (and including) the
* center element in the range. These elements will be used for
* pivot selection as described below. The choice for spacing
* these elements was empirically determined to work well on
* a wide variety of inputs.
*/
int e3 = (left + right) >>> 1; // The midpoint
int e2 = e3 - seventh;
int e1 = e2 - seventh;
int e4 = e3 + seventh;
int e5 = e4 + seventh;
// Sort these elements using insertion sort
if (a[e2] < a[e1]) { long t = a[e2]; a[e2] = a[e1]; a[e1] = t; }
if (a[e3] < a[e2]) { long t = a[e3]; a[e3] = a[e2]; a[e2] = t;
if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
}
if (a[e4] < a[e3]) { long t = a[e4]; a[e4] = a[e3]; a[e3] = t;
if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
}
}
if (a[e5] < a[e4]) { long t = a[e5]; a[e5] = a[e4]; a[e4] = t;
if (t < a[e3]) { a[e4] = a[e3]; a[e3] = t;
if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
}
}
}
/*
* Use the second and fourth of the five sorted elements as pivots.
* These values are inexpensive approximations of the first and
* second terciles of the array. Note that pivot1 <= pivot2.
*/
long pivot1 = a[e2];
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
* locations formerly occupied by the pivots. When partitioning
* is complete, the pivots are swapped back into their final
* positions, and excluded from subsequent sorting.
*/
a[e2] = a[left];
a[e4] = a[right];
/*
* Skip elements, which are less or greater than pivot values.
*/
while (a[++less] < pivot1);
while (a[--great] > pivot2);
/*
* Partitioning:
*
* left part center part right part
* +--------------------------------------------------------------+
* | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 |
* +--------------------------------------------------------------+
* ^ ^ ^
* | | |
* less k great
*
* Invariants:
*
* all in (left, less) < pivot1
* pivot1 <= all in [less, k) <= pivot2
* all in (great, right) > pivot2
*
* Pointer k is the first index of ?-part.
*/
outer:
for (int k = less; k <= great; k++) {
long ak = a[k];
if (ak < pivot1) { // Move a[k] to left part
a[k] = a[less];
a[less] = ak;
less++;
} else if (ak > pivot2) { // Move a[k] to right part
while (a[great] > pivot2) {
if (great-- == k) {
break outer;
}
}
if (a[great] < pivot1) {
a[k] = a[less];
a[less] = a[great];
less++;
} else { // pivot1 <= a[great] <= pivot2
a[k] = a[great];
}
a[great] = ak;
great--;
}
}
// Swap pivots into their final positions
a[left] = a[less - 1]; a[less - 1] = pivot1;
a[right] = a[great + 1]; a[great + 1] = pivot2;
// Sort left and right parts recursively, excluding known pivots
sort(a, left, less - 2, leftmost);
sort(a, great + 2, right, false);
/*
* If center part is too large (comprises > 5/7 of the array),
* swap internal pivot values to ends.
*/
if (less < e1 && e5 < great) {
/* /*
* Skip elements, which are equal to pivot values. * Skip the longest ascending sequence.
*/ */
while (a[less] == pivot1) { do {
less++; if (left++ >= right) {
} return;
while (a[great] == pivot2) { }
great--; } while (a[left - 1] <= a[left]);
}
/* /*
* Partitioning: * Every element from adjoining part plays the role
* * of sentinel, therefore this allows us to avoid the
* left part center part right part * left range check on each iteration. Moreover, we use
* +----------------------------------------------------------+ * the best improved algorithm, so called pair insertion
* | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 | * sort, which is faster than traditional implementation
* +----------------------------------------------------------+ * in the context of Dual-Pivot Quicksort.
* ^ ^ ^
* | | |
* less k great
*
* Invariants:
*
* all in (*, less) == pivot1
* pivot1 < all in [less, k) < pivot2
* all in (great, *) == pivot2
*
* Pointer k is the first index of ?-part.
*/ */
outer: for (int k = left--; (left += 2) <= right; ) {
for (int k = less; k <= great; k++) { long a1, a2; k = left - 1;
long ak = a[k];
if (ak == pivot1) { // Move a[k] to left part
a[k] = a[less];
a[less] = ak;
less++;
} else if (ak == pivot2) { // Move a[k] to right part
while (a[great] == pivot2) {
if (great-- == k) {
break outer;
}
}
if (a[great] == pivot1) {
a[k] = a[less];
/*
* Even though a[great] equals to pivot1, the
* assignment a[less] = pivot1 may be incorrect,
* if a[great] and pivot1 are floating-point zeros
* of different signs. Therefore in float and
* double sorting methods we have to use more
* accurate assignment a[less] = a[great].
*/
a[less] = pivot1;
less++;
} else { // pivot1 < a[great] < pivot2
a[k] = a[great];
}
a[great] = ak;
great--;
}
}
}
// Sort center part recursively if (a[k] < a[left]) {
sort(a, less, great, false); a2 = a[k]; a1 = a[left];
} else {
} else { // Pivots are equal a1 = a[k]; a2 = a[left];
/*
* Partition degenerates to the traditional 3-way
* (or "Dutch National Flag") schema:
*
* left part center part right part
* +-------------------------------------------------+
* | < pivot | == pivot | ? | > pivot |
* +-------------------------------------------------+
* ^ ^ ^
* | | |
* less k great
*
* Invariants:
*
* all in (left, less) < pivot
* all in [less, k) == pivot
* all in (great, right) > pivot
*
* Pointer k is the first index of ?-part.
*/
for (int k = left; k <= great; k++) {
if (a[k] == pivot1) {
continue;
}
long ak = a[k];
if (ak < pivot1) { // Move a[k] to left part
a[k] = a[less];
a[less] = ak;
less++;
} else { // a[k] > pivot1 - Move a[k] to right part
/*
* We know that pivot1 == a[e3] == pivot2. Thus, we know
* that great will still be >= k when the following loop
* terminates, even though we don't test for it explicitly.
* In other words, a[e3] acts as a sentinel for great.
*/
while (a[great] > pivot1) {
// assert great > k;
great--;
} }
if (a[great] < pivot1) { while (a1 < a[--k]) {
a[k] = a[less]; a[k + 2] = a[k];
a[less] = a[great];
less++;
} else { // a[great] == pivot1
/*
* Even though a[great] equals to pivot1, the
* assignment a[k] = pivot1 may be incorrect,
* if a[great] and pivot1 are floating-point
* zeros of different signs. Therefore in float
* and double sorting methods we have to use
* more accurate assignment a[k] = a[great].
*/
a[k] = pivot1;
} }
a[great] = ak; a[++k + 1] = a1;
great--;
}
}
// Sort left and right parts recursively
sort(a, left, less - 1, leftmost);
sort(a, great + 1, right, false);
}
}
/** while (a2 < a[--k]) {
* Sorts the specified array into ascending numerical order. a[k + 1] = a[k];
*
* @param a the array to be sorted
*/
public static void sort(short[] a) {
if (a.length > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) {
countingSort(a, 0, a.length - 1);
} else {
sort(a, 0, a.length - 1, true);
}
}
/**
* Sorts the specified range of the array into ascending order. The range
* to be sorted extends from the index {@code fromIndex}, inclusive, to
* the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
* the range to be sorted is empty (and the call is a no-op).
*
* @param a the array to be sorted
* @param fromIndex the index of the first element, inclusive, to be sorted
* @param toIndex the index of the last element, exclusive, to be sorted
* @throws IllegalArgumentException if {@code fromIndex > toIndex}
* @throws ArrayIndexOutOfBoundsException
* if {@code fromIndex < 0} or {@code toIndex > a.length}
*/
public static void sort(short[] a, int fromIndex, int toIndex) {
rangeCheck(a.length, fromIndex, toIndex);
if (toIndex - fromIndex > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) {
countingSort(a, fromIndex, toIndex - 1);
} else {
sort(a, fromIndex, toIndex - 1, true);
}
}
/** The number of distinct short values. */
private static final int NUM_SHORT_VALUES = 1 << 16;
/**
* Sorts the specified range of the array by counting sort.
*
* @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 countingSort(short[] a, int left, int right) {
int[] count = new int[NUM_SHORT_VALUES];
for (int i = left; i <= right; i++) {
count[a[i] - Short.MIN_VALUE]++;
}
for (int i = NUM_SHORT_VALUES - 1, k = right; k >= left; i--) {
while (count[i] == 0) {
i--;
}
short value = (short) (i + Short.MIN_VALUE);
int s = count[i];
do {
a[k--] = value;
} while (--s > 0);
}
}
/**
* Sorts the specified range of the array into ascending order by the
* Dual-Pivot Quicksort algorithm. This method differs from the public
* {@code sort} method in that the {@code right} index is inclusive,
* it does no range checking on {@code left} or {@code right}, and has
* boolean flag whether insertion sort with sentinel is used or not.
*
* @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
* @param leftmost indicates if the part is the most left in the range
*/
private static void sort(short[] a, int left, int right,boolean leftmost) {
int length = right - left + 1;
// Use insertion sort on tiny arrays
if (length < INSERTION_SORT_THRESHOLD) {
if (!leftmost) {
/*
* Every element in adjoining part plays the role
* of sentinel, therefore this allows us to avoid
* the j >= left check on each iteration.
*/
for (int j, i = left + 1; i <= right; i++) {
short ai = a[i];
for (j = i - 1; ai < a[j]; j--) {
// assert j >= left;
a[j + 1] = a[j];
} }
a[j + 1] = ai; a[k + 1] = a2;
} }
} else { long last = a[right];
/*
* For case of leftmost part traditional (without a sentinel) while (last < a[--right]) {
* insertion sort, optimized for server JVM, is used. a[right + 1] = a[right];
*/
for (int i = left, j = i; i < right; j = ++i) {
short ai = a[i + 1];
while (ai < a[j]) {
a[j + 1] = a[j];
if (j-- == left) {
break;
}
}
a[j + 1] = ai;
} }
a[right + 1] = last;
} }
return; return;
} }
// Inexpensive approximation of length / 7 // Inexpensive approximation of length / 7
int seventh = (length >>> 3) + (length >>> 6) + 1; int seventh = (length >> 3) + (length >> 6) + 1;
/* /*
* Sort five evenly spaced elements around (and including) the * Sort five evenly spaced elements around (and including) the
...@@ -866,17 +537,17 @@ final class DualPivotQuicksort { ...@@ -866,17 +537,17 @@ final class DualPivotQuicksort {
int e5 = e4 + seventh; int e5 = e4 + seventh;
// Sort these elements using insertion sort // Sort these elements using insertion sort
if (a[e2] < a[e1]) { short t = a[e2]; a[e2] = a[e1]; a[e1] = t; } if (a[e2] < a[e1]) { long t = a[e2]; a[e2] = a[e1]; a[e1] = t; }
if (a[e3] < a[e2]) { short t = a[e3]; a[e3] = a[e2]; a[e2] = t; if (a[e3] < a[e2]) { long t = a[e3]; a[e3] = a[e2]; a[e2] = t;
if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
} }
if (a[e4] < a[e3]) { short t = a[e4]; a[e4] = a[e3]; a[e3] = t; if (a[e4] < a[e3]) { long t = a[e4]; a[e4] = a[e3]; a[e3] = t;
if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t; if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
} }
} }
if (a[e5] < a[e4]) { short t = a[e5]; a[e5] = a[e4]; a[e4] = t; if (a[e5] < a[e4]) { long t = a[e5]; a[e5] = a[e4]; a[e4] = t;
if (t < a[e3]) { a[e4] = a[e3]; a[e3] = t; if (t < a[e3]) { a[e4] = a[e3]; a[e3] = t;
if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t; if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
...@@ -889,8 +560,8 @@ final class DualPivotQuicksort { ...@@ -889,8 +560,8 @@ final class DualPivotQuicksort {
* These values are inexpensive approximations of the first and * These values are inexpensive approximations of the first and
* second terciles of the array. Note that pivot1 <= pivot2. * second terciles of the array. Note that pivot1 <= pivot2.
*/ */
short pivot1 = a[e2]; long pivot1 = a[e2];
short pivot2 = a[e4]; long pivot2 = a[e4];
// Pointers // Pointers
int less = left; // The index of the first element of center part int less = left; // The index of the first element of center part
...@@ -932,10 +603,14 @@ final class DualPivotQuicksort { ...@@ -932,10 +603,14 @@ final class DualPivotQuicksort {
* Pointer k is the first index of ?-part. * Pointer k is the first index of ?-part.
*/ */
outer: outer:
for (int k = less; k <= great; k++) { for (int k = less - 1; ++k <= great; ) {
short ak = a[k]; long ak = a[k];
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];
/*
* Here and below we use "a[i] = b; i++;" instead
* 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
...@@ -944,13 +619,17 @@ final class DualPivotQuicksort { ...@@ -944,13 +619,17 @@ final class DualPivotQuicksort {
break outer; break outer;
} }
} }
if (a[great] < pivot1) { 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];
} }
/*
* Here and below we use "a[i] = b; i--;" instead
* of "a[i--] = b;" due to performance issue.
*/
a[great] = ak; a[great] = ak;
great--; great--;
} }
...@@ -965,7 +644,7 @@ final class DualPivotQuicksort { ...@@ -965,7 +644,7 @@ final class DualPivotQuicksort {
sort(a, great + 2, right, false); sort(a, great + 2, right, false);
/* /*
* If center part is too large (comprises > 5/7 of the array), * If center part is too large (comprises > 4/7 of the array),
* swap internal pivot values to ends. * swap internal pivot values to ends.
*/ */
if (less < e1 && e5 < great) { if (less < e1 && e5 < great) {
...@@ -999,8 +678,8 @@ final class DualPivotQuicksort { ...@@ -999,8 +678,8 @@ final class DualPivotQuicksort {
* Pointer k is the first index of ?-part. * Pointer k is the first index of ?-part.
*/ */
outer: outer:
for (int k = less; k <= great; k++) { for (int k = less - 1; ++k <= great; ) {
short ak = a[k]; long ak = a[k];
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;
...@@ -1011,7 +690,7 @@ final class DualPivotQuicksort { ...@@ -1011,7 +690,7 @@ final class DualPivotQuicksort {
break outer; break outer;
} }
} }
if (a[great] == pivot1) { if (a[great] == pivot1) { // a[great] < pivot2
a[k] = a[less]; a[k] = a[less];
/* /*
* Even though a[great] equals to pivot1, the * Even though a[great] equals to pivot1, the
...@@ -1037,7 +716,7 @@ final class DualPivotQuicksort { ...@@ -1037,7 +716,7 @@ final class DualPivotQuicksort {
} else { // Pivots are equal } else { // Pivots are equal
/* /*
* Partition degenerates to the traditional 3-way * Partitioning degenerates to the traditional 3-way
* (or "Dutch National Flag") schema: * (or "Dutch National Flag") schema:
* *
* left part center part right part * left part center part right part
...@@ -1056,28 +735,20 @@ final class DualPivotQuicksort { ...@@ -1056,28 +735,20 @@ final class DualPivotQuicksort {
* *
* Pointer k is the first index of ?-part. * Pointer k is the first index of ?-part.
*/ */
for (int k = left; k <= great; k++) { for (int k = less; k <= great; ++k) {
if (a[k] == pivot1) { if (a[k] == pivot1) {
continue; continue;
} }
short ak = a[k]; long ak = a[k];
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 { // a[k] > pivot1 - Move a[k] to right part } else { // a[k] > pivot1 - Move a[k] to right part
/*
* We know that pivot1 == a[e3] == pivot2. Thus, we know
* that great will still be >= k when the following loop
* terminates, even though we don't test for it explicitly.
* In other words, a[e3] acts as a sentinel for great.
*/
while (a[great] > pivot1) { while (a[great] > pivot1) {
// assert great > k;
great--; great--;
} }
if (a[great] < pivot1) { if (a[great] < pivot1) { // a[great] <= pivot1
a[k] = a[less]; a[k] = a[less];
a[less] = a[great]; a[less] = a[great];
less++; less++;
...@@ -1097,115 +768,78 @@ final class DualPivotQuicksort { ...@@ -1097,115 +768,78 @@ final class DualPivotQuicksort {
} }
} }
// Sort left and right parts recursively /*
* Sort left and right parts recursively.
* All elements from center part are equal
* and, therefore, already sorted.
*/
sort(a, left, less - 1, leftmost); sort(a, left, less - 1, leftmost);
sort(a, great + 1, right, false); sort(a, great + 1, right, false);
} }
} }
/** /**
* Sorts the specified array into ascending numerical order. * Sorts the specified array.
*
* @param a the array to be sorted
*/
public static void sort(char[] a) {
if (a.length > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) {
countingSort(a, 0, a.length - 1);
} else {
sort(a, 0, a.length - 1, true);
}
}
/**
* Sorts the specified range of the array into ascending order. The range
* to be sorted extends from the index {@code fromIndex}, inclusive, to
* the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
* the range to be sorted is empty (and the call is a no-op).
* *
* @param a the array to be sorted * @param a the array to be sorted
* @param fromIndex the index of the first element, inclusive, to be sorted
* @param toIndex the index of the last element, exclusive, to be sorted
* @throws IllegalArgumentException if {@code fromIndex > toIndex}
* @throws ArrayIndexOutOfBoundsException
* if {@code fromIndex < 0} or {@code toIndex > a.length}
*/ */
public static void sort(char[] a, int fromIndex, int toIndex) { public static void sort(short[] a) {
rangeCheck(a.length, fromIndex, toIndex); sort(a, 0, a.length - 1);
if (toIndex - fromIndex > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) {
countingSort(a, fromIndex, toIndex - 1);
} else {
sort(a, fromIndex, toIndex - 1, true);
}
} }
/** The number of distinct char values. */
private static final int NUM_CHAR_VALUES = 1 << 16;
/** /**
* Sorts the specified range of the array by counting sort. * Sorts the specified range of the array.
* *
* @param a the array to be sorted * @param a the array to be sorted
* @param left the index of the first element, inclusive, 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 * @param right the index of the last element, inclusive, to be sorted
*/ */
private static void countingSort(char[] a, int left, int right) { public static void sort(short[] a, int left, int right) {
int[] count = new int[NUM_CHAR_VALUES]; // Use counting sort on large arrays
if (right - left > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) {
int[] count = new int[NUM_SHORT_VALUES];
for (int i = left; i <= right; i++) { for (int i = left - 1; ++i <= right; ) {
count[a[i]]++; count[a[i] - Short.MIN_VALUE]++;
}
for (int i = 0, k = left; k <= right; i++) {
while (count[i] == 0) {
i++;
} }
char value = (char) i; for (int i = NUM_SHORT_VALUES, k = right + 1; k > left; ) {
int s = count[i]; while (count[--i] == 0);
short value = (short) (i + Short.MIN_VALUE);
do { int s = count[i];
a[k++] = value;
} while (--s > 0); do {
a[--k] = value;
} while (--s > 0);
}
} else { // Use Dual-Pivot Quicksort on small arrays
sort(a, left, right, true);
} }
} }
/** The number of distinct short values. */
private static final int NUM_SHORT_VALUES = 1 << 16;
/** /**
* Sorts the specified range of the array into ascending order by the * Sorts the specified range of the array by Dual-Pivot Quicksort.
* Dual-Pivot Quicksort algorithm. This method differs from the public
* {@code sort} method in that the {@code right} index is inclusive,
* it does no range checking on {@code left} or {@code right}, and has
* boolean flag whether insertion sort with sentinel is used or not.
* *
* @param a the array to be sorted * @param a the array to be sorted
* @param left the index of the first element, inclusive, 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 * @param right the index of the last element, inclusive, to be sorted
* @param leftmost indicates if the part is the most left in the range * @param leftmost indicates if this part is the leftmost in the range
*/ */
private static void sort(char[] 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 tiny arrays // Use insertion sort on small arrays
if (length < INSERTION_SORT_THRESHOLD) { if (length < INSERTION_SORT_THRESHOLD) {
if (!leftmost) { if (leftmost) {
/*
* Every element in adjoining part plays the role
* of sentinel, therefore this allows us to avoid
* the j >= left check on each iteration.
*/
for (int j, i = left + 1; i <= right; i++) {
char ai = a[i];
for (j = i - 1; ai < a[j]; j--) {
// assert j >= left;
a[j + 1] = a[j];
}
a[j + 1] = ai;
}
} else {
/* /*
* For case of leftmost part traditional (without a sentinel) * Traditional (without sentinel) insertion sort,
* insertion sort, optimized for server JVM, is used. * optimized for server VM, is used in case of
* the leftmost part.
*/ */
for (int i = left, j = i; i < right; j = ++i) { for (int i = left, j = i; i < right; j = ++i) {
char ai = a[i + 1]; short ai = a[i + 1];
while (ai < a[j]) { while (ai < a[j]) {
a[j + 1] = a[j]; a[j + 1] = a[j];
if (j-- == left) { if (j-- == left) {
...@@ -1214,12 +848,54 @@ final class DualPivotQuicksort { ...@@ -1214,12 +848,54 @@ final class DualPivotQuicksort {
} }
a[j + 1] = ai; a[j + 1] = ai;
} }
} else {
/*
* Skip the longest ascending sequence.
*/
do {
if (left++ >= right) {
return;
}
} while (a[left - 1] <= a[left]);
/*
* Every element from adjoining part plays the role
* of sentinel, therefore this allows us to avoid the
* left range check on each iteration. Moreover, we use
* the best improved algorithm, so called pair insertion
* sort, which is faster than traditional implementation
* in the context of Dual-Pivot Quicksort.
*/
for (int k = left--; (left += 2) <= right; ) {
short a1, a2; k = left - 1;
if (a[k] < a[left]) {
a2 = a[k]; a1 = a[left];
} else {
a1 = a[k]; a2 = a[left];
}
while (a1 < a[--k]) {
a[k + 2] = a[k];
}
a[++k + 1] = a1;
while (a2 < a[--k]) {
a[k + 1] = a[k];
}
a[k + 1] = a2;
}
short last = a[right];
while (last < a[--right]) {
a[right + 1] = a[right];
}
a[right + 1] = last;
} }
return; return;
} }
// Inexpensive approximation of length / 7 // Inexpensive approximation of length / 7
int seventh = (length >>> 3) + (length >>> 6) + 1; int seventh = (length >> 3) + (length >> 6) + 1;
/* /*
* Sort five evenly spaced elements around (and including) the * Sort five evenly spaced elements around (and including) the
...@@ -1235,17 +911,17 @@ final class DualPivotQuicksort { ...@@ -1235,17 +911,17 @@ final class DualPivotQuicksort {
int e5 = e4 + seventh; int e5 = e4 + seventh;
// Sort these elements using insertion sort // Sort these elements using insertion sort
if (a[e2] < a[e1]) { char t = a[e2]; a[e2] = a[e1]; a[e1] = t; } if (a[e2] < a[e1]) { short t = a[e2]; a[e2] = a[e1]; a[e1] = t; }
if (a[e3] < a[e2]) { char t = a[e3]; a[e3] = a[e2]; a[e2] = t; if (a[e3] < a[e2]) { short t = a[e3]; a[e3] = a[e2]; a[e2] = t;
if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
} }
if (a[e4] < a[e3]) { char t = a[e4]; a[e4] = a[e3]; a[e3] = t; if (a[e4] < a[e3]) { short t = a[e4]; a[e4] = a[e3]; a[e3] = t;
if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t; if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
} }
} }
if (a[e5] < a[e4]) { char t = a[e5]; a[e5] = a[e4]; a[e4] = t; if (a[e5] < a[e4]) { short t = a[e5]; a[e5] = a[e4]; a[e4] = t;
if (t < a[e3]) { a[e4] = a[e3]; a[e3] = t; if (t < a[e3]) { a[e4] = a[e3]; a[e3] = t;
if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t; if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
...@@ -1258,8 +934,8 @@ final class DualPivotQuicksort { ...@@ -1258,8 +934,8 @@ final class DualPivotQuicksort {
* These values are inexpensive approximations of the first and * These values are inexpensive approximations of the first and
* second terciles of the array. Note that pivot1 <= pivot2. * second terciles of the array. Note that pivot1 <= pivot2.
*/ */
char pivot1 = a[e2]; short pivot1 = a[e2];
char pivot2 = a[e4]; short pivot2 = a[e4];
// Pointers // Pointers
int less = left; // The index of the first element of center part int less = left; // The index of the first element of center part
...@@ -1301,10 +977,14 @@ final class DualPivotQuicksort { ...@@ -1301,10 +977,14 @@ final class DualPivotQuicksort {
* Pointer k is the first index of ?-part. * Pointer k is the first index of ?-part.
*/ */
outer: outer:
for (int k = less; k <= great; k++) { for (int k = less - 1; ++k <= great; ) {
char ak = a[k]; short ak = a[k];
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];
/*
* Here and below we use "a[i] = b; i++;" instead
* 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
...@@ -1313,13 +993,17 @@ final class DualPivotQuicksort { ...@@ -1313,13 +993,17 @@ final class DualPivotQuicksort {
break outer; break outer;
} }
} }
if (a[great] < pivot1) { 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];
} }
/*
* Here and below we use "a[i] = b; i--;" instead
* of "a[i--] = b;" due to performance issue.
*/
a[great] = ak; a[great] = ak;
great--; great--;
} }
...@@ -1334,7 +1018,7 @@ final class DualPivotQuicksort { ...@@ -1334,7 +1018,7 @@ final class DualPivotQuicksort {
sort(a, great + 2, right, false); sort(a, great + 2, right, false);
/* /*
* If center part is too large (comprises > 5/7 of the array), * If center part is too large (comprises > 4/7 of the array),
* swap internal pivot values to ends. * swap internal pivot values to ends.
*/ */
if (less < e1 && e5 < great) { if (less < e1 && e5 < great) {
...@@ -1368,8 +1052,8 @@ final class DualPivotQuicksort { ...@@ -1368,8 +1052,8 @@ final class DualPivotQuicksort {
* Pointer k is the first index of ?-part. * Pointer k is the first index of ?-part.
*/ */
outer: outer:
for (int k = less; k <= great; k++) { for (int k = less - 1; ++k <= great; ) {
char ak = a[k]; short ak = a[k];
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;
...@@ -1380,7 +1064,7 @@ final class DualPivotQuicksort { ...@@ -1380,7 +1064,7 @@ final class DualPivotQuicksort {
break outer; break outer;
} }
} }
if (a[great] == pivot1) { if (a[great] == pivot1) { // a[great] < pivot2
a[k] = a[less]; a[k] = a[less];
/* /*
* Even though a[great] equals to pivot1, the * Even though a[great] equals to pivot1, the
...@@ -1406,7 +1090,7 @@ final class DualPivotQuicksort { ...@@ -1406,7 +1090,7 @@ final class DualPivotQuicksort {
} else { // Pivots are equal } else { // Pivots are equal
/* /*
* Partition degenerates to the traditional 3-way * Partitioning degenerates to the traditional 3-way
* (or "Dutch National Flag") schema: * (or "Dutch National Flag") schema:
* *
* left part center part right part * left part center part right part
...@@ -1425,28 +1109,20 @@ final class DualPivotQuicksort { ...@@ -1425,28 +1109,20 @@ final class DualPivotQuicksort {
* *
* Pointer k is the first index of ?-part. * Pointer k is the first index of ?-part.
*/ */
for (int k = left; k <= great; k++) { for (int k = less; k <= great; ++k) {
if (a[k] == pivot1) { if (a[k] == pivot1) {
continue; continue;
} }
char ak = a[k]; short ak = a[k];
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 { // a[k] > pivot1 - Move a[k] to right part } else { // a[k] > pivot1 - Move a[k] to right part
/*
* We know that pivot1 == a[e3] == pivot2. Thus, we know
* that great will still be >= k when the following loop
* terminates, even though we don't test for it explicitly.
* In other words, a[e3] acts as a sentinel for great.
*/
while (a[great] > pivot1) { while (a[great] > pivot1) {
// assert great > k;
great--; great--;
} }
if (a[great] < pivot1) { if (a[great] < pivot1) { // a[great] <= pivot1
a[k] = a[less]; a[k] = a[less];
a[less] = a[great]; a[less] = a[great];
less++; less++;
...@@ -1466,115 +1142,78 @@ final class DualPivotQuicksort { ...@@ -1466,115 +1142,78 @@ final class DualPivotQuicksort {
} }
} }
// Sort left and right parts recursively /*
* Sort left and right parts recursively.
* All elements from center part are equal
* and, therefore, already sorted.
*/
sort(a, left, less - 1, leftmost); sort(a, left, less - 1, leftmost);
sort(a, great + 1, right, false); sort(a, great + 1, right, false);
} }
} }
/** /**
* Sorts the specified array into ascending numerical order. * Sorts the specified array.
* *
* @param a the array to be sorted * @param a the array to be sorted
*/ */
public static void sort(byte[] a) { public static void sort(char[] a) {
if (a.length > COUNTING_SORT_THRESHOLD_FOR_BYTE) { sort(a, 0, a.length - 1);
countingSort(a, 0, a.length - 1);
} else {
sort(a, 0, a.length - 1, true);
}
}
/**
* Sorts the specified range of the array into ascending order. The range
* to be sorted extends from the index {@code fromIndex}, inclusive, to
* the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
* the range to be sorted is empty (and the call is a no-op).
*
* @param a the array to be sorted
* @param fromIndex the index of the first element, inclusive, to be sorted
* @param toIndex the index of the last element, exclusive, to be sorted
* @throws IllegalArgumentException if {@code fromIndex > toIndex}
* @throws ArrayIndexOutOfBoundsException
* if {@code fromIndex < 0} or {@code toIndex > a.length}
*/
public static void sort(byte[] a, int fromIndex, int toIndex) {
rangeCheck(a.length, fromIndex, toIndex);
if (toIndex - fromIndex > COUNTING_SORT_THRESHOLD_FOR_BYTE) {
countingSort(a, fromIndex, toIndex - 1);
} else {
sort(a, fromIndex, toIndex - 1, true);
}
} }
/** The number of distinct byte values. */
private static final int NUM_BYTE_VALUES = 1 << 8;
/** /**
* Sorts the specified range of the array by counting sort. * Sorts the specified range of the array.
* *
* @param a the array to be sorted * @param a the array to be sorted
* @param left the index of the first element, inclusive, 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 * @param right the index of the last element, inclusive, to be sorted
*/ */
private static void countingSort(byte[] a, int left, int right) { public static void sort(char[] a, int left, int right) {
int[] count = new int[NUM_BYTE_VALUES]; // Use counting sort on large arrays
if (right - left > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) {
int[] count = new int[NUM_CHAR_VALUES];
for (int i = left; i <= right; i++) { for (int i = left - 1; ++i <= right; ) {
count[a[i] - Byte.MIN_VALUE]++; count[a[i]]++;
}
for (int i = NUM_BYTE_VALUES - 1, k = right; k >= left; i--) {
while (count[i] == 0) {
i--;
} }
byte value = (byte) (i + Byte.MIN_VALUE); for (int i = NUM_CHAR_VALUES, k = right + 1; k > left; ) {
int s = count[i]; while (count[--i] == 0);
char value = (char) i;
do { int s = count[i];
a[k--] = value;
} while (--s > 0); do {
a[--k] = value;
} while (--s > 0);
}
} else { // Use Dual-Pivot Quicksort on small arrays
sort(a, left, right, true);
} }
} }
/** The number of distinct char values. */
private static final int NUM_CHAR_VALUES = 1 << 16;
/** /**
* Sorts the specified range of the array into ascending order by the * Sorts the specified range of the array by Dual-Pivot Quicksort.
* Dual-Pivot Quicksort algorithm. This method differs from the public
* {@code sort} method in that the {@code right} index is inclusive,
* it does no range checking on {@code left} or {@code right}, and has
* boolean flag whether insertion sort with sentinel is used or not.
* *
* @param a the array to be sorted * @param a the array to be sorted
* @param left the index of the first element, inclusive, 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 * @param right the index of the last element, inclusive, to be sorted
* @param leftmost indicates if the part is the most left in the range * @param leftmost indicates if this part is the leftmost in the range
*/ */
private static void sort(byte[] 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 tiny arrays // Use insertion sort on small arrays
if (length < INSERTION_SORT_THRESHOLD) { if (length < INSERTION_SORT_THRESHOLD) {
if (!leftmost) { if (leftmost) {
/*
* Every element in adjoining part plays the role
* of sentinel, therefore this allows us to avoid
* the j >= left check on each iteration.
*/
for (int j, i = left + 1; i <= right; i++) {
byte ai = a[i];
for (j = i - 1; ai < a[j]; j--) {
// assert j >= left;
a[j + 1] = a[j];
}
a[j + 1] = ai;
}
} else {
/* /*
* For case of leftmost part traditional (without a sentinel) * Traditional (without sentinel) insertion sort,
* insertion sort, optimized for server JVM, is used. * optimized for server VM, is used in case of
* the leftmost part.
*/ */
for (int i = left, j = i; i < right; j = ++i) { for (int i = left, j = i; i < right; j = ++i) {
byte ai = a[i + 1]; char ai = a[i + 1];
while (ai < a[j]) { while (ai < a[j]) {
a[j + 1] = a[j]; a[j + 1] = a[j];
if (j-- == left) { if (j-- == left) {
...@@ -1583,12 +1222,54 @@ final class DualPivotQuicksort { ...@@ -1583,12 +1222,54 @@ final class DualPivotQuicksort {
} }
a[j + 1] = ai; a[j + 1] = ai;
} }
} else {
/*
* Skip the longest ascending sequence.
*/
do {
if (left++ >= right) {
return;
}
} while (a[left - 1] <= a[left]);
/*
* Every element from adjoining part plays the role
* of sentinel, therefore this allows us to avoid the
* left range check on each iteration. Moreover, we use
* the best improved algorithm, so called pair insertion
* sort, which is faster than traditional implementation
* in the context of Dual-Pivot Quicksort.
*/
for (int k = left--; (left += 2) <= right; ) {
char a1, a2; k = left - 1;
if (a[k] < a[left]) {
a2 = a[k]; a1 = a[left];
} else {
a1 = a[k]; a2 = a[left];
}
while (a1 < a[--k]) {
a[k + 2] = a[k];
}
a[++k + 1] = a1;
while (a2 < a[--k]) {
a[k + 1] = a[k];
}
a[k + 1] = a2;
}
char last = a[right];
while (last < a[--right]) {
a[right + 1] = a[right];
}
a[right + 1] = last;
} }
return; return;
} }
// Inexpensive approximation of length / 7 // Inexpensive approximation of length / 7
int seventh = (length >>> 3) + (length >>> 6) + 1; int seventh = (length >> 3) + (length >> 6) + 1;
/* /*
* Sort five evenly spaced elements around (and including) the * Sort five evenly spaced elements around (and including) the
...@@ -1604,17 +1285,17 @@ final class DualPivotQuicksort { ...@@ -1604,17 +1285,17 @@ final class DualPivotQuicksort {
int e5 = e4 + seventh; int e5 = e4 + seventh;
// Sort these elements using insertion sort // Sort these elements using insertion sort
if (a[e2] < a[e1]) { byte t = a[e2]; a[e2] = a[e1]; a[e1] = t; } if (a[e2] < a[e1]) { char t = a[e2]; a[e2] = a[e1]; a[e1] = t; }
if (a[e3] < a[e2]) { byte t = a[e3]; a[e3] = a[e2]; a[e2] = t; if (a[e3] < a[e2]) { char t = a[e3]; a[e3] = a[e2]; a[e2] = t;
if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
} }
if (a[e4] < a[e3]) { byte t = a[e4]; a[e4] = a[e3]; a[e3] = t; if (a[e4] < a[e3]) { char t = a[e4]; a[e4] = a[e3]; a[e3] = t;
if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t; if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
} }
} }
if (a[e5] < a[e4]) { byte t = a[e5]; a[e5] = a[e4]; a[e4] = t; if (a[e5] < a[e4]) { char t = a[e5]; a[e5] = a[e4]; a[e4] = t;
if (t < a[e3]) { a[e4] = a[e3]; a[e3] = t; if (t < a[e3]) { a[e4] = a[e3]; a[e3] = t;
if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t; if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
...@@ -1627,8 +1308,8 @@ final class DualPivotQuicksort { ...@@ -1627,8 +1308,8 @@ final class DualPivotQuicksort {
* These values are inexpensive approximations of the first and * These values are inexpensive approximations of the first and
* second terciles of the array. Note that pivot1 <= pivot2. * second terciles of the array. Note that pivot1 <= pivot2.
*/ */
byte pivot1 = a[e2]; char pivot1 = a[e2];
byte pivot2 = a[e4]; char pivot2 = a[e4];
// Pointers // Pointers
int less = left; // The index of the first element of center part int less = left; // The index of the first element of center part
...@@ -1670,10 +1351,14 @@ final class DualPivotQuicksort { ...@@ -1670,10 +1351,14 @@ final class DualPivotQuicksort {
* Pointer k is the first index of ?-part. * Pointer k is the first index of ?-part.
*/ */
outer: outer:
for (int k = less; k <= great; k++) { for (int k = less - 1; ++k <= great; ) {
byte ak = a[k]; char ak = a[k];
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];
/*
* Here and below we use "a[i] = b; i++;" instead
* 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
...@@ -1682,13 +1367,17 @@ final class DualPivotQuicksort { ...@@ -1682,13 +1367,17 @@ final class DualPivotQuicksort {
break outer; break outer;
} }
} }
if (a[great] < pivot1) { 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];
} }
/*
* Here and below we use "a[i] = b; i--;" instead
* of "a[i--] = b;" due to performance issue.
*/
a[great] = ak; a[great] = ak;
great--; great--;
} }
...@@ -1703,7 +1392,7 @@ final class DualPivotQuicksort { ...@@ -1703,7 +1392,7 @@ final class DualPivotQuicksort {
sort(a, great + 2, right, false); sort(a, great + 2, right, false);
/* /*
* If center part is too large (comprises > 5/7 of the array), * If center part is too large (comprises > 4/7 of the array),
* swap internal pivot values to ends. * swap internal pivot values to ends.
*/ */
if (less < e1 && e5 < great) { if (less < e1 && e5 < great) {
...@@ -1737,8 +1426,8 @@ final class DualPivotQuicksort { ...@@ -1737,8 +1426,8 @@ final class DualPivotQuicksort {
* Pointer k is the first index of ?-part. * Pointer k is the first index of ?-part.
*/ */
outer: outer:
for (int k = less; k <= great; k++) { for (int k = less - 1; ++k <= great; ) {
byte ak = a[k]; char ak = a[k];
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;
...@@ -1749,7 +1438,7 @@ final class DualPivotQuicksort { ...@@ -1749,7 +1438,7 @@ final class DualPivotQuicksort {
break outer; break outer;
} }
} }
if (a[great] == pivot1) { if (a[great] == pivot1) { // a[great] < pivot2
a[k] = a[less]; a[k] = a[less];
/* /*
* Even though a[great] equals to pivot1, the * Even though a[great] equals to pivot1, the
...@@ -1775,7 +1464,7 @@ final class DualPivotQuicksort { ...@@ -1775,7 +1464,7 @@ final class DualPivotQuicksort {
} else { // Pivots are equal } else { // Pivots are equal
/* /*
* Partition degenerates to the traditional 3-way * Partitioning degenerates to the traditional 3-way
* (or "Dutch National Flag") schema: * (or "Dutch National Flag") schema:
* *
* left part center part right part * left part center part right part
...@@ -1794,28 +1483,20 @@ final class DualPivotQuicksort { ...@@ -1794,28 +1483,20 @@ final class DualPivotQuicksort {
* *
* Pointer k is the first index of ?-part. * Pointer k is the first index of ?-part.
*/ */
for (int k = left; k <= great; k++) { for (int k = less; k <= great; ++k) {
if (a[k] == pivot1) { if (a[k] == pivot1) {
continue; continue;
} }
byte ak = a[k]; char ak = a[k];
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 { // a[k] > pivot1 - Move a[k] to right part } else { // a[k] > pivot1 - Move a[k] to right part
/*
* We know that pivot1 == a[e3] == pivot2. Thus, we know
* that great will still be >= k when the following loop
* terminates, even though we don't test for it explicitly.
* In other words, a[e3] acts as a sentinel for great.
*/
while (a[great] > pivot1) { while (a[great] > pivot1) {
// assert great > k;
great--; great--;
} }
if (a[great] < pivot1) { if (a[great] < pivot1) { // a[great] <= pivot1
a[k] = a[less]; a[k] = a[less];
a[less] = a[great]; a[less] = a[great];
less++; less++;
...@@ -1835,73 +1516,90 @@ final class DualPivotQuicksort { ...@@ -1835,73 +1516,90 @@ final class DualPivotQuicksort {
} }
} }
// Sort left and right parts recursively /*
* Sort left and right parts recursively.
* All elements from center part are equal
* and, therefore, already sorted.
*/
sort(a, left, less - 1, leftmost); sort(a, left, less - 1, leftmost);
sort(a, great + 1, right, false); sort(a, great + 1, right, false);
} }
} }
/** The number of distinct byte values. */
private static final int NUM_BYTE_VALUES = 1 << 8;
/** /**
* Sorts the specified array into ascending numerical order. * Sorts the specified array.
*
* <p>The {@code <} relation does not provide a total order on all float
* values: {@code -0.0f == 0.0f} is {@code true} and a {@code Float.NaN}
* value compares neither less than, greater than, nor equal to any value,
* even itself. This method uses the total order imposed by the method
* {@link Float#compareTo}: {@code -0.0f} is treated as less than value
* {@code 0.0f} and {@code Float.NaN} is considered greater than any
* other value and all {@code Float.NaN} values are considered equal.
* *
* @param a the array to be sorted * @param a the array to be sorted
*/ */
public static void sort(float[] a) { public static void sort(byte[] a) {
sortNegZeroAndNaN(a, 0, a.length - 1); sort(a, 0, a.length - 1);
} }
/** /**
* Sorts the specified range of the array into ascending order. The range * Sorts the specified range of the array.
* to be sorted extends from the index {@code fromIndex}, inclusive, to
* the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
* the range to be sorted is empty (and the call is a no-op).
* *
* <p>The {@code <} relation does not provide a total order on all float * @param a the array to be sorted
* values: {@code -0.0f == 0.0f} is {@code true} and a {@code Float.NaN} * @param left the index of the first element, inclusive, to be sorted
* value compares neither less than, greater than, nor equal to any value, * @param right the index of the last element, inclusive, to be sorted
* even itself. This method uses the total order imposed by the method */
* {@link Float#compareTo}: {@code -0.0f} is treated as less than value public static void sort(byte[] a, int left, int right) {
* {@code 0.0f} and {@code Float.NaN} is considered greater than any // Use counting sort on large arrays
* other value and all {@code Float.NaN} values are considered equal. if (right - left > COUNTING_SORT_THRESHOLD_FOR_BYTE) {
int[] count = new int[NUM_BYTE_VALUES];
for (int i = left - 1; ++i <= right; ) {
count[a[i] - Byte.MIN_VALUE]++;
}
for (int i = NUM_BYTE_VALUES, k = right + 1; k > left; ) {
while (count[--i] == 0);
byte value = (byte) (i + Byte.MIN_VALUE);
int s = count[i];
do {
a[--k] = value;
} while (--s > 0);
}
} else { // Use insertion sort on small arrays
for (int i = left, j = i; i < right; j = ++i) {
byte ai = a[i + 1];
while (ai < a[j]) {
a[j + 1] = a[j];
if (j-- == left) {
break;
}
}
a[j + 1] = ai;
}
}
}
/**
* Sorts the specified array.
* *
* @param a the array to be sorted * @param a the array to be sorted
* @param fromIndex the index of the first element, inclusive, to be sorted
* @param toIndex the index of the last element, exclusive, to be sorted
* @throws IllegalArgumentException if {@code fromIndex > toIndex}
* @throws ArrayIndexOutOfBoundsException
* if {@code fromIndex < 0} or {@code toIndex > a.length}
*/ */
public static void sort(float[] a, int fromIndex, int toIndex) { public static void sort(float[] a) {
rangeCheck(a.length, fromIndex, toIndex); sort(a, 0, a.length - 1);
sortNegZeroAndNaN(a, fromIndex, toIndex - 1);
} }
/** /**
* Sorts the specified range of the array into ascending order. The * Sorts the specified range of the array.
* sort is done in three phases to avoid expensive comparisons in the
* inner loop. The comparisons would be expensive due to anomalies
* associated with negative zero {@code -0.0f} and {@code Float.NaN}.
* *
* @param a the array to be sorted * @param a the array to be sorted
* @param left the index of the first element, inclusive, 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 * @param right the index of the last element, inclusive, to be sorted
*/ */
private static void sortNegZeroAndNaN(float[] a, int left, int right) { public static void sort(float[] a, int left, int right) {
/* /*
* 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 - 1; k >= left; k--) { 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];
...@@ -1921,7 +1619,7 @@ final class DualPivotQuicksort { ...@@ -1921,7 +1619,7 @@ final class DualPivotQuicksort {
int hi = right; int hi = right;
/* /*
* Search first zero, or first positive, or last negative element. * Find the first zero, or first positive, or last negative element.
*/ */
while (left < hi) { while (left < hi) {
int middle = (left + hi) >>> 1; int middle = (left + hi) >>> 1;
...@@ -1946,12 +1644,12 @@ final class DualPivotQuicksort { ...@@ -1946,12 +1644,12 @@ final class DualPivotQuicksort {
* *
* Partitioning: * Partitioning:
* *
* +---------------------------------------------------+ * +----------------------------------------------------+
* | < 0.0 | -0.0 | 0.0 | ? ( >= 0.0 ) | * | < 0.0 | -0.0 | 0.0 | ? ( >= 0.0 ) |
* +---------------------------------------------------+ * +----------------------------------------------------+
* ^ ^ ^ * ^ ^ ^
* | | | * | | |
* left p k * left p k
* *
* Invariants: * Invariants:
* *
...@@ -1962,53 +1660,36 @@ final class DualPivotQuicksort { ...@@ -1962,53 +1660,36 @@ final class DualPivotQuicksort {
* *
* Pointer k is the first index of ?-part. * Pointer k is the first index of ?-part.
*/ */
for (int k = left + 1, p = left; k <= right; k++) { for (int k = left, p = left - 1; ++k <= right; ) {
float ak = a[k]; float ak = a[k];
if (ak != 0.0f) { if (ak != 0.0f) {
break; break;
} }
if (Float.floatToRawIntBits(ak) < 0) { // ak is -0.0f if (Float.floatToRawIntBits(ak) < 0) { // ak is -0.0f
a[k] = 0.0f; a[k] = 0.0f;
a[p++] = -0.0f; a[++p] = -0.0f;
} }
} }
} }
/** /**
* Sorts the specified range of the array into ascending order by the * Sorts the specified range of the array by Dual-Pivot Quicksort.
* Dual-Pivot Quicksort algorithm. This method differs from the public
* {@code sort} method in that the {@code right} index is inclusive,
* it does no range checking on {@code left} or {@code right}, and has
* boolean flag whether insertion sort with sentinel is used or not.
* *
* @param a the array to be sorted * @param a the array to be sorted
* @param left the index of the first element, inclusive, 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 * @param right the index of the last element, inclusive, to be sorted
* @param leftmost indicates if the part is the most left 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 tiny arrays // Use insertion sort on small arrays
if (length < INSERTION_SORT_THRESHOLD) { if (length < INSERTION_SORT_THRESHOLD) {
if (!leftmost) { if (leftmost) {
/*
* Every element in adjoining part plays the role
* of sentinel, therefore this allows us to avoid
* the j >= left check on each iteration.
*/
for (int j, i = left + 1; i <= right; i++) {
float ai = a[i];
for (j = i - 1; ai < a[j]; j--) {
// assert j >= left;
a[j + 1] = a[j];
}
a[j + 1] = ai;
}
} else {
/* /*
* For case of leftmost part traditional (without a sentinel) * Traditional (without sentinel) insertion sort,
* insertion sort, optimized for server JVM, is used. * optimized for server VM, is used in case of
* the leftmost part.
*/ */
for (int i = left, j = i; i < right; j = ++i) { for (int i = left, j = i; i < right; j = ++i) {
float ai = a[i + 1]; float ai = a[i + 1];
...@@ -2020,12 +1701,54 @@ final class DualPivotQuicksort { ...@@ -2020,12 +1701,54 @@ final class DualPivotQuicksort {
} }
a[j + 1] = ai; a[j + 1] = ai;
} }
} else {
/*
* Skip the longest ascending sequence.
*/
do {
if (left++ >= right) {
return;
}
} while (a[left - 1] <= a[left]);
/*
* Every element from adjoining part plays the role
* of sentinel, therefore this allows us to avoid the
* left range check on each iteration. Moreover, we use
* the best improved algorithm, so called pair insertion
* sort, which is faster than traditional implementation
* in the context of Dual-Pivot Quicksort.
*/
for (int k = left--; (left += 2) <= right; ) {
float a1, a2; k = left - 1;
if (a[k] < a[left]) {
a2 = a[k]; a1 = a[left];
} else {
a1 = a[k]; a2 = a[left];
}
while (a1 < a[--k]) {
a[k + 2] = a[k];
}
a[++k + 1] = a1;
while (a2 < a[--k]) {
a[k + 1] = a[k];
}
a[k + 1] = a2;
}
float last = a[right];
while (last < a[--right]) {
a[right + 1] = a[right];
}
a[right + 1] = last;
} }
return; return;
} }
// Inexpensive approximation of length / 7 // Inexpensive approximation of length / 7
int seventh = (length >>> 3) + (length >>> 6) + 1; int seventh = (length >> 3) + (length >> 6) + 1;
/* /*
* Sort five evenly spaced elements around (and including) the * Sort five evenly spaced elements around (and including) the
...@@ -2107,10 +1830,14 @@ final class DualPivotQuicksort { ...@@ -2107,10 +1830,14 @@ final class DualPivotQuicksort {
* Pointer k is the first index of ?-part. * Pointer k is the first index of ?-part.
*/ */
outer: outer:
for (int k = less; k <= great; k++) { for (int k = less - 1; ++k <= great; ) {
float ak = a[k]; float ak = a[k];
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];
/*
* Here and below we use "a[i] = b; i++;" instead
* 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
...@@ -2119,13 +1846,17 @@ final class DualPivotQuicksort { ...@@ -2119,13 +1846,17 @@ final class DualPivotQuicksort {
break outer; break outer;
} }
} }
if (a[great] < pivot1) { 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];
} }
/*
* Here and below we use "a[i] = b; i--;" instead
* of "a[i--] = b;" due to performance issue.
*/
a[great] = ak; a[great] = ak;
great--; great--;
} }
...@@ -2140,7 +1871,7 @@ final class DualPivotQuicksort { ...@@ -2140,7 +1871,7 @@ final class DualPivotQuicksort {
sort(a, great + 2, right, false); sort(a, great + 2, right, false);
/* /*
* If center part is too large (comprises > 5/7 of the array), * If center part is too large (comprises > 4/7 of the array),
* swap internal pivot values to ends. * swap internal pivot values to ends.
*/ */
if (less < e1 && e5 < great) { if (less < e1 && e5 < great) {
...@@ -2174,7 +1905,7 @@ final class DualPivotQuicksort { ...@@ -2174,7 +1905,7 @@ final class DualPivotQuicksort {
* Pointer k is the first index of ?-part. * Pointer k is the first index of ?-part.
*/ */
outer: outer:
for (int k = less; k <= great; k++) { for (int k = less - 1; ++k <= great; ) {
float ak = a[k]; float ak = a[k];
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];
...@@ -2186,7 +1917,7 @@ final class DualPivotQuicksort { ...@@ -2186,7 +1917,7 @@ final class DualPivotQuicksort {
break outer; break outer;
} }
} }
if (a[great] == pivot1) { if (a[great] == pivot1) { // a[great] < pivot2
a[k] = a[less]; a[k] = a[less];
/* /*
* Even though a[great] equals to pivot1, the * Even though a[great] equals to pivot1, the
...@@ -2212,7 +1943,7 @@ final class DualPivotQuicksort { ...@@ -2212,7 +1943,7 @@ final class DualPivotQuicksort {
} else { // Pivots are equal } else { // Pivots are equal
/* /*
* Partition degenerates to the traditional 3-way * Partitioning degenerates to the traditional 3-way
* (or "Dutch National Flag") schema: * (or "Dutch National Flag") schema:
* *
* left part center part right part * left part center part right part
...@@ -2231,28 +1962,20 @@ final class DualPivotQuicksort { ...@@ -2231,28 +1962,20 @@ final class DualPivotQuicksort {
* *
* Pointer k is the first index of ?-part. * Pointer k is the first index of ?-part.
*/ */
for (int k = left; k <= great; k++) { for (int k = less; k <= great; ++k) {
if (a[k] == pivot1) { if (a[k] == pivot1) {
continue; continue;
} }
float ak = a[k]; float ak = a[k];
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 { // a[k] > pivot1 - Move a[k] to right part } else { // a[k] > pivot1 - Move a[k] to right part
/*
* We know that pivot1 == a[e3] == pivot2. Thus, we know
* that great will still be >= k when the following loop
* terminates, even though we don't test for it explicitly.
* In other words, a[e3] acts as a sentinel for great.
*/
while (a[great] > pivot1) { while (a[great] > pivot1) {
// assert great > k;
great--; great--;
} }
if (a[great] < pivot1) { if (a[great] < pivot1) { // a[great] <= pivot1
a[k] = a[less]; a[k] = a[less];
a[less] = a[great]; a[less] = a[great];
less++; less++;
...@@ -2272,73 +1995,40 @@ final class DualPivotQuicksort { ...@@ -2272,73 +1995,40 @@ final class DualPivotQuicksort {
} }
} }
// Sort left and right parts recursively /*
* Sort left and right parts recursively.
* All elements from center part are equal
* and, therefore, already sorted.
*/
sort(a, left, less - 1, leftmost); sort(a, left, less - 1, leftmost);
sort(a, great + 1, right, false); sort(a, great + 1, right, false);
} }
} }
/** /**
* Sorts the specified array into ascending numerical order. * Sorts the specified array.
*
* <p>The {@code <} relation does not provide a total order on all double
* values: {@code -0.0d == 0.0d} is {@code true} and a {@code Double.NaN}
* value compares neither less than, greater than, nor equal to any value,
* even itself. This method uses the total order imposed by the method
* {@link Double#compareTo}: {@code -0.0d} is treated as less than value
* {@code 0.0d} and {@code Double.NaN} is considered greater than any
* other value and all {@code Double.NaN} values are considered equal.
* *
* @param a the array to be sorted * @param a the array to be sorted
*/ */
public static void sort(double[] a) { public static void sort(double[] a) {
sortNegZeroAndNaN(a, 0, a.length - 1); sort(a, 0, a.length - 1);
}
/**
* Sorts the specified range of the array into ascending order. The range
* to be sorted extends from the index {@code fromIndex}, inclusive, to
* the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
* the range to be sorted is empty (and the call is a no-op).
*
* <p>The {@code <} relation does not provide a total order on all double
* values: {@code -0.0d == 0.0d} is {@code true} and a {@code Double.NaN}
* value compares neither less than, greater than, nor equal to any value,
* even itself. This method uses the total order imposed by the method
* {@link Double#compareTo}: {@code -0.0d} is treated as less than value
* {@code 0.0d} and {@code Double.NaN} is considered greater than any
* other value and all {@code Double.NaN} values are considered equal.
*
* @param a the array to be sorted
* @param fromIndex the index of the first element, inclusive, to be sorted
* @param toIndex the index of the last element, exclusive, to be sorted
* @throws IllegalArgumentException if {@code fromIndex > toIndex}
* @throws ArrayIndexOutOfBoundsException
* if {@code fromIndex < 0} or {@code toIndex > a.length}
*/
public static void sort(double[] a, int fromIndex, int toIndex) {
rangeCheck(a.length, fromIndex, toIndex);
sortNegZeroAndNaN(a, fromIndex, toIndex - 1);
} }
/** /**
* Sorts the specified range of the array into ascending order. The * Sorts the specified range of the array.
* sort is done in three phases to avoid expensive comparisons in the
* inner loop. The comparisons would be expensive due to anomalies
* associated with negative zero {@code -0.0d} and {@code Double.NaN}.
* *
* @param a the array to be sorted * @param a the array to be sorted
* @param left the index of the first element, inclusive, 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 * @param right the index of the last element, inclusive, to be sorted
*/ */
private static void sortNegZeroAndNaN(double[] a, int left, int right) { public static void sort(double[] a, int left, int right) {
/* /*
* 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 - 1; k >= left; k--) { 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];
...@@ -2358,7 +2048,7 @@ final class DualPivotQuicksort { ...@@ -2358,7 +2048,7 @@ final class DualPivotQuicksort {
int hi = right; int hi = right;
/* /*
* Search first zero, or first positive, or last negative element. * Find the first zero, or first positive, or last negative element.
*/ */
while (left < hi) { while (left < hi) {
int middle = (left + hi) >>> 1; int middle = (left + hi) >>> 1;
...@@ -2383,12 +2073,12 @@ final class DualPivotQuicksort { ...@@ -2383,12 +2073,12 @@ final class DualPivotQuicksort {
* *
* Partitioning: * Partitioning:
* *
* +---------------------------------------------------+ * +----------------------------------------------------+
* | < 0.0 | -0.0 | 0.0 | ? ( >= 0.0 ) | * | < 0.0 | -0.0 | 0.0 | ? ( >= 0.0 ) |
* +---------------------------------------------------+ * +----------------------------------------------------+
* ^ ^ ^ * ^ ^ ^
* | | | * | | |
* left p k * left p k
* *
* Invariants: * Invariants:
* *
...@@ -2399,53 +2089,36 @@ final class DualPivotQuicksort { ...@@ -2399,53 +2089,36 @@ final class DualPivotQuicksort {
* *
* Pointer k is the first index of ?-part. * Pointer k is the first index of ?-part.
*/ */
for (int k = left + 1, p = left; k <= right; k++) { for (int k = left, p = left - 1; ++k <= right; ) {
double ak = a[k]; double ak = a[k];
if (ak != 0.0d) { if (ak != 0.0d) {
break; break;
} }
if (Double.doubleToRawLongBits(ak) < 0) { // ak is -0.0d if (Double.doubleToRawLongBits(ak) < 0) { // ak is -0.0d
a[k] = 0.0d; a[k] = 0.0d;
a[p++] = -0.0d; a[++p] = -0.0d;
} }
} }
} }
/** /**
* Sorts the specified range of the array into ascending order by the * Sorts the specified range of the array by Dual-Pivot Quicksort.
* Dual-Pivot Quicksort algorithm. This method differs from the public
* {@code sort} method in that the {@code right} index is inclusive,
* it does no range checking on {@code left} or {@code right}, and has
* boolean flag whether insertion sort with sentinel is used or not.
* *
* @param a the array to be sorted * @param a the array to be sorted
* @param left the index of the first element, inclusive, 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 * @param right the index of the last element, inclusive, to be sorted
* @param leftmost indicates if the part is the most left 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 tiny arrays // Use insertion sort on small arrays
if (length < INSERTION_SORT_THRESHOLD) { if (length < INSERTION_SORT_THRESHOLD) {
if (!leftmost) { if (leftmost) {
/*
* Every element in adjoining part plays the role
* of sentinel, therefore this allows us to avoid
* the j >= left check on each iteration.
*/
for (int j, i = left + 1; i <= right; i++) {
double ai = a[i];
for (j = i - 1; ai < a[j]; j--) {
// assert j >= left;
a[j + 1] = a[j];
}
a[j + 1] = ai;
}
} else {
/* /*
* For case of leftmost part traditional (without a sentinel) * Traditional (without sentinel) insertion sort,
* insertion sort, optimized for server JVM, is used. * optimized for server VM, is used in case of
* the leftmost part.
*/ */
for (int i = left, j = i; i < right; j = ++i) { for (int i = left, j = i; i < right; j = ++i) {
double ai = a[i + 1]; double ai = a[i + 1];
...@@ -2457,12 +2130,54 @@ final class DualPivotQuicksort { ...@@ -2457,12 +2130,54 @@ final class DualPivotQuicksort {
} }
a[j + 1] = ai; a[j + 1] = ai;
} }
} else {
/*
* Skip the longest ascending sequence.
*/
do {
if (left++ >= right) {
return;
}
} while (a[left - 1] <= a[left]);
/*
* Every element from adjoining part plays the role
* of sentinel, therefore this allows us to avoid the
* left range check on each iteration. Moreover, we use
* the best improved algorithm, so called pair insertion
* sort, which is faster than traditional implementation
* in the context of Dual-Pivot Quicksort.
*/
for (int k = left--; (left += 2) <= right; ) {
double a1, a2; k = left - 1;
if (a[k] < a[left]) {
a2 = a[k]; a1 = a[left];
} else {
a1 = a[k]; a2 = a[left];
}
while (a1 < a[--k]) {
a[k + 2] = a[k];
}
a[++k + 1] = a1;
while (a2 < a[--k]) {
a[k + 1] = a[k];
}
a[k + 1] = a2;
}
double last = a[right];
while (last < a[--right]) {
a[right + 1] = a[right];
}
a[right + 1] = last;
} }
return; return;
} }
// Inexpensive approximation of length / 7 // Inexpensive approximation of length / 7
int seventh = (length >>> 3) + (length >>> 6) + 1; int seventh = (length >> 3) + (length >> 6) + 1;
/* /*
* Sort five evenly spaced elements around (and including) the * Sort five evenly spaced elements around (and including) the
...@@ -2544,10 +2259,14 @@ final class DualPivotQuicksort { ...@@ -2544,10 +2259,14 @@ final class DualPivotQuicksort {
* Pointer k is the first index of ?-part. * Pointer k is the first index of ?-part.
*/ */
outer: outer:
for (int k = less; k <= great; k++) { for (int k = less - 1; ++k <= great; ) {
double ak = a[k]; double ak = a[k];
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];
/*
* Here and below we use "a[i] = b; i++;" instead
* 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
...@@ -2556,13 +2275,17 @@ final class DualPivotQuicksort { ...@@ -2556,13 +2275,17 @@ final class DualPivotQuicksort {
break outer; break outer;
} }
} }
if (a[great] < pivot1) { 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];
} }
/*
* Here and below we use "a[i] = b; i--;" instead
* of "a[i--] = b;" due to performance issue.
*/
a[great] = ak; a[great] = ak;
great--; great--;
} }
...@@ -2577,7 +2300,7 @@ final class DualPivotQuicksort { ...@@ -2577,7 +2300,7 @@ final class DualPivotQuicksort {
sort(a, great + 2, right, false); sort(a, great + 2, right, false);
/* /*
* If center part is too large (comprises > 5/7 of the array), * If center part is too large (comprises > 4/7 of the array),
* swap internal pivot values to ends. * swap internal pivot values to ends.
*/ */
if (less < e1 && e5 < great) { if (less < e1 && e5 < great) {
...@@ -2611,7 +2334,7 @@ final class DualPivotQuicksort { ...@@ -2611,7 +2334,7 @@ final class DualPivotQuicksort {
* Pointer k is the first index of ?-part. * Pointer k is the first index of ?-part.
*/ */
outer: outer:
for (int k = less; k <= great; k++) { for (int k = less - 1; ++k <= great; ) {
double ak = a[k]; double ak = a[k];
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];
...@@ -2623,7 +2346,7 @@ final class DualPivotQuicksort { ...@@ -2623,7 +2346,7 @@ final class DualPivotQuicksort {
break outer; break outer;
} }
} }
if (a[great] == pivot1) { if (a[great] == pivot1) { // a[great] < pivot2
a[k] = a[less]; a[k] = a[less];
/* /*
* Even though a[great] equals to pivot1, the * Even though a[great] equals to pivot1, the
...@@ -2649,7 +2372,7 @@ final class DualPivotQuicksort { ...@@ -2649,7 +2372,7 @@ final class DualPivotQuicksort {
} else { // Pivots are equal } else { // Pivots are equal
/* /*
* Partition degenerates to the traditional 3-way * Partitioning degenerates to the traditional 3-way
* (or "Dutch National Flag") schema: * (or "Dutch National Flag") schema:
* *
* left part center part right part * left part center part right part
...@@ -2668,28 +2391,20 @@ final class DualPivotQuicksort { ...@@ -2668,28 +2391,20 @@ final class DualPivotQuicksort {
* *
* Pointer k is the first index of ?-part. * Pointer k is the first index of ?-part.
*/ */
for (int k = left; k <= great; k++) { for (int k = less; k <= great; ++k) {
if (a[k] == pivot1) { if (a[k] == pivot1) {
continue; continue;
} }
double ak = a[k]; double ak = a[k];
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 { // a[k] > pivot1 - Move a[k] to right part } else { // a[k] > pivot1 - Move a[k] to right part
/*
* We know that pivot1 == a[e3] == pivot2. Thus, we know
* that great will still be >= k when the following loop
* terminates, even though we don't test for it explicitly.
* In other words, a[e3] acts as a sentinel for great.
*/
while (a[great] > pivot1) { while (a[great] > pivot1) {
// assert great > k;
great--; great--;
} }
if (a[great] < pivot1) { if (a[great] < pivot1) { // a[great] <= pivot1
a[k] = a[less]; a[k] = a[less];
a[less] = a[great]; a[less] = a[great];
less++; less++;
...@@ -2709,26 +2424,13 @@ final class DualPivotQuicksort { ...@@ -2709,26 +2424,13 @@ final class DualPivotQuicksort {
} }
} }
// Sort left and right parts recursively /*
* Sort left and right parts recursively.
* All elements from center part are equal
* and, therefore, already sorted.
*/
sort(a, left, less - 1, leftmost); sort(a, left, less - 1, leftmost);
sort(a, great + 1, right, false); sort(a, great + 1, right, false);
} }
} }
/**
* Checks that {@code fromIndex} and {@code toIndex} are in the range,
* otherwise throws an appropriate exception.
*/
private static void rangeCheck(int length, int fromIndex, int toIndex) {
if (fromIndex > toIndex) {
throw new IllegalArgumentException(
"fromIndex: " + fromIndex + " > toIndex: " + toIndex);
}
if (fromIndex < 0) {
throw new ArrayIndexOutOfBoundsException(fromIndex);
}
if (toIndex > length) {
throw new ArrayIndexOutOfBoundsException(toIndex);
}
}
} }
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
/* /*
* @test * @test
* @bug 6880672 6896573 6899694 * @bug 6880672 6896573 6899694 6976036
* @summary Exercise Arrays.sort * @summary Exercise Arrays.sort
* @build Sorting * @build Sorting
* @run main Sorting -shortrun * @run main Sorting -shortrun
...@@ -50,10 +50,10 @@ public class Sorting { ...@@ -50,10 +50,10 @@ public class Sorting {
1, 2, 3, 21, 55, 1000, 10000 }; 1, 2, 3, 21, 55, 1000, 10000 };
// Random initial values used in a long run (default) // Random initial values used in a long run (default)
private static final long[] LONG_RUN_RANDOMS = {666, 0xC0FFEE, 999}; private static final long[] LONG_RUN_RANDOMS = { 666, 0xC0FFEE, 999 };
// Random initial values used in a short run // Random initial values used in a short run
private static final long[] SHORT_RUN_RANDOMS = {666}; private static final long[] SHORT_RUN_RANDOMS = { 666 };
public static void main(String[] args) { public static void main(String[] args) {
boolean shortRun = args.length > 0 && args[0].equals("-shortrun"); boolean shortRun = args.length > 0 && args[0].equals("-shortrun");
...@@ -81,6 +81,11 @@ public class Sorting { ...@@ -81,6 +81,11 @@ public class Sorting {
for (long random : randoms) { for (long random : randoms) {
reset(random); reset(random);
for (int length : lengths) {
testAndCheckWithInsertionSort(length, random);
}
reset(random);
for (int length : lengths) { for (int length : lengths) {
testAndCheckWithCheckSum(length, random); testAndCheckWithCheckSum(length, random);
} }
...@@ -268,9 +273,7 @@ public class Sorting { ...@@ -268,9 +273,7 @@ public class Sorting {
" length = " + length + ", m = " + m); " length = " + length + ", m = " + m);
Object convertedGolden = converter.convert(golden); Object convertedGolden = converter.convert(golden);
Object convertedTest = converter.convert(test); Object convertedTest = converter.convert(test);
// outArray(test);
sortSubArray(convertedTest, fromIndex, toIndex); sortSubArray(convertedTest, fromIndex, toIndex);
// outArray(test);
checkSubArray(convertedTest, fromIndex, toIndex, m); checkSubArray(convertedTest, fromIndex, toIndex, m);
} }
} }
...@@ -311,7 +314,7 @@ public class Sorting { ...@@ -311,7 +314,7 @@ public class Sorting {
private static void checkSorted(Pair[] a) { private static void checkSorted(Pair[] a) {
for (int i = 0; i < a.length - 1; i++) { for (int i = 0; i < a.length - 1; i++) {
if (a[i].getKey() > a[i + 1].getKey()) { if (a[i].getKey() > a[i + 1].getKey()) {
failed(i, "" + a[i].getKey(), "" + a[i + 1].getKey()); failedSort(i, "" + a[i].getKey(), "" + a[i + 1].getKey());
} }
} }
} }
...@@ -328,7 +331,7 @@ public class Sorting { ...@@ -328,7 +331,7 @@ public class Sorting {
int value4 = a[i++].getValue(); int value4 = a[i++].getValue();
if (!(key1 == key2 && key2 == key3 && key3 == key4)) { if (!(key1 == key2 && key2 == key3 && key3 == key4)) {
failed("On position " + i + " must keys are different " + failed("On position " + i + " keys are different " +
key1 + ", " + key2 + ", " + key3 + ", " + key4); key1 + ", " + key2 + ", " + key3 + ", " + key4);
} }
if (!(value1 < value2 && value2 < value3 && value3 < value4)) { if (!(value1 < value2 && value2 < value3 && value3 < value4)) {
...@@ -385,6 +388,35 @@ public class Sorting { ...@@ -385,6 +388,35 @@ public class Sorting {
private int myValue; private int myValue;
} }
private static void testAndCheckWithInsertionSort(int length, long random) {
if (length > 1000) {
return;
}
ourDescription = "Check sorting with insertion sort";
int[] golden = new int[length];
for (int m = 1; m < 2 * length; m *= 2) {
for (UnsortedBuilder builder : UnsortedBuilder.values()) {
builder.build(golden, m);
int[] test = golden.clone();
for (TypeConverter converter : TypeConverter.values()) {
out.println("Test 'insertion sort': " + converter + " " +
builder + "random = " + random + ", length = " +
length + ", m = " + m);
Object convertedGolden = converter.convert(golden);
Object convertedTest1 = converter.convert(test);
Object convertedTest2 = converter.convert(test);
sort(convertedTest1);
sortByInsertionSort(convertedTest2);
compare(convertedTest1, convertedTest2);
}
}
}
out.println();
}
private static void testAndCheckWithCheckSum(int length, long random) { private static void testAndCheckWithCheckSum(int length, long random) {
ourDescription = "Check sorting with check sum"; ourDescription = "Check sorting with check sum";
int[] golden = new int[length]; int[] golden = new int[length];
...@@ -460,9 +492,7 @@ public class Sorting { ...@@ -460,9 +492,7 @@ public class Sorting {
builder.build(golden, a, g, z, n, p); builder.build(golden, a, g, z, n, p);
float[] test = golden.clone(); float[] test = golden.clone();
scramble(test); scramble(test);
// outArray(test);
sort(test); sort(test);
// outArray(test);
compare(test, golden, a, n, g); compare(test, golden, a, n, g);
} }
newLine = true; newLine = true;
...@@ -500,9 +530,7 @@ public class Sorting { ...@@ -500,9 +530,7 @@ public class Sorting {
builder.build(golden, a, g, z, n, p); builder.build(golden, a, g, z, n, p);
double[] test = golden.clone(); double[] test = golden.clone();
scramble(test); scramble(test);
// outArray(test);
sort(test); sort(test);
// outArray(test);
compare(test, golden, a, n, g); compare(test, golden, a, n, g);
} }
newLine = true; newLine = true;
...@@ -721,12 +749,12 @@ public class Sorting { ...@@ -721,12 +749,12 @@ public class Sorting {
for (int i = numNeg; i < numNeg + numNegZero; i++) { for (int i = numNeg; i < numNeg + numNegZero; i++) {
if (NEGATIVE_ZERO != Float.floatToIntBits(a[i])) { if (NEGATIVE_ZERO != Float.floatToIntBits(a[i])) {
failed("On position " + i + " must be -0.0f instead of " + a[i]); failed("On position " + i + " must be -0.0 instead of " + a[i]);
} }
} }
for (int i = 0; i < a.length - numNaN; i++) { for (int i = 0; i < a.length - numNaN; i++) {
if (a[i] != b[i]) { if (a[i] != b[i]) {
failed(i, "" + a[i], "" + b[i]); failedCompare(i, "" + a[i], "" + b[i]);
} }
} }
} }
...@@ -747,12 +775,12 @@ public class Sorting { ...@@ -747,12 +775,12 @@ public class Sorting {
for (int i = numNeg; i < numNeg + numNegZero; i++) { for (int i = numNeg; i < numNeg + numNegZero; i++) {
if (NEGATIVE_ZERO != Double.doubleToLongBits(a[i])) { if (NEGATIVE_ZERO != Double.doubleToLongBits(a[i])) {
failed("On position " + i + " must be -0.0d instead of " + a[i]); failed("On position " + i + " must be -0.0 instead of " + a[i]);
} }
} }
for (int i = 0; i < a.length - numNaN; i++) { for (int i = 0; i < a.length - numNaN; i++) {
if (a[i] != b[i]) { if (a[i] != b[i]) {
failed(i, "" + a[i], "" + b[i]); failedCompare(i, "" + a[i], "" + b[i]);
} }
} }
} }
...@@ -841,8 +869,8 @@ public class Sorting { ...@@ -841,8 +869,8 @@ public class Sorting {
int incCount = 1; int incCount = 1;
int decCount = a.length; int decCount = a.length;
int i = 0; int i = 0;
int period = m; int period = m--;
m--;
while (true) { while (true) {
for (int k = 1; k <= period; k++) { for (int k = 1; k <= period; k++) {
if (i >= a.length) { if (i >= a.length) {
...@@ -922,6 +950,25 @@ public class Sorting { ...@@ -922,6 +950,25 @@ public class Sorting {
} }
} }
private static void checkWithCheckSum(Object test, Object golden) {
checkSorted(test);
checkCheckSum(test, golden);
}
private static void failed(String message) {
err.format("\n*** TEST FAILED - %s.\n\n%s.\n\n", ourDescription, message);
throw new RuntimeException("Test failed - see log file for details");
}
private static void failedSort(int index, String value1, String value2) {
failed("Array is not sorted at " + index + "-th position: " +
value1 + " and " + value2);
}
private static void failedCompare(int index, String value1, String value2) {
failed("On position " + index + " must be " + value2 + " instead of " + value1);
}
private static void compare(Object test, Object golden) { private static void compare(Object test, Object golden) {
if (test instanceof int[]) { if (test instanceof int[]) {
compare((int[]) test, (int[]) golden); compare((int[]) test, (int[]) golden);
...@@ -945,56 +992,10 @@ public class Sorting { ...@@ -945,56 +992,10 @@ public class Sorting {
} }
} }
private static void checkWithCheckSum(Object test, Object golden) {
checkSorted(test);
checkCheckSum(test, golden);
}
private static void failed(String message) {
err.format("\n*** TEST FAILED - %s\n\n%s\n\n", ourDescription, message);
throw new RuntimeException("Test failed - see log file for details");
}
private static void failed(int index, String value1, String value2) {
failed("Array is not sorted at " + index + "-th position: " +
value1 + " and " + value2);
}
private static void checkSorted(Object object) {
if (object instanceof int[]) {
checkSorted((int[]) object);
} else if (object instanceof long[]) {
checkSorted((long[]) object);
} else if (object instanceof short[]) {
checkSorted((short[]) object);
} else if (object instanceof byte[]) {
checkSorted((byte[]) object);
} else if (object instanceof char[]) {
checkSorted((char[]) object);
} else if (object instanceof float[]) {
checkSorted((float[]) object);
} else if (object instanceof double[]) {
checkSorted((double[]) object);
} else if (object instanceof Integer[]) {
checkSorted((Integer[]) object);
} else {
failed("Unknow type of array: " + object + " of class " +
object.getClass().getName());
}
}
private static void compare(Integer[] a, Integer[] b) {
for (int i = 0; i < a.length; i++) {
if (a[i].intValue() != b[i].intValue()) {
failed(i, "" + a[i], "" + b[i]);
}
}
}
private static void compare(int[] a, int[] b) { private static void compare(int[] a, int[] b) {
for (int i = 0; i < a.length; i++) { for (int i = 0; i < a.length; i++) {
if (a[i] != b[i]) { if (a[i] != b[i]) {
failed(i, "" + a[i], "" + b[i]); failedCompare(i, "" + a[i], "" + b[i]);
} }
} }
} }
...@@ -1002,7 +1003,7 @@ public class Sorting { ...@@ -1002,7 +1003,7 @@ public class Sorting {
private static void compare(long[] a, long[] b) { private static void compare(long[] a, long[] b) {
for (int i = 0; i < a.length; i++) { for (int i = 0; i < a.length; i++) {
if (a[i] != b[i]) { if (a[i] != b[i]) {
failed(i, "" + a[i], "" + b[i]); failedCompare(i, "" + a[i], "" + b[i]);
} }
} }
} }
...@@ -1010,7 +1011,7 @@ public class Sorting { ...@@ -1010,7 +1011,7 @@ public class Sorting {
private static void compare(short[] a, short[] b) { private static void compare(short[] a, short[] b) {
for (int i = 0; i < a.length; i++) { for (int i = 0; i < a.length; i++) {
if (a[i] != b[i]) { if (a[i] != b[i]) {
failed(i, "" + a[i], "" + b[i]); failedCompare(i, "" + a[i], "" + b[i]);
} }
} }
} }
...@@ -1018,7 +1019,7 @@ public class Sorting { ...@@ -1018,7 +1019,7 @@ public class Sorting {
private static void compare(byte[] a, byte[] b) { private static void compare(byte[] a, byte[] b) {
for (int i = 0; i < a.length; i++) { for (int i = 0; i < a.length; i++) {
if (a[i] != b[i]) { if (a[i] != b[i]) {
failed(i, "" + a[i], "" + b[i]); failedCompare(i, "" + a[i], "" + b[i]);
} }
} }
} }
...@@ -1026,7 +1027,7 @@ public class Sorting { ...@@ -1026,7 +1027,7 @@ public class Sorting {
private static void compare(char[] a, char[] b) { private static void compare(char[] a, char[] b) {
for (int i = 0; i < a.length; i++) { for (int i = 0; i < a.length; i++) {
if (a[i] != b[i]) { if (a[i] != b[i]) {
failed(i, "" + a[i], "" + b[i]); failedCompare(i, "" + a[i], "" + b[i]);
} }
} }
} }
...@@ -1034,7 +1035,7 @@ public class Sorting { ...@@ -1034,7 +1035,7 @@ public class Sorting {
private static void compare(float[] a, float[] b) { private static void compare(float[] a, float[] b) {
for (int i = 0; i < a.length; i++) { for (int i = 0; i < a.length; i++) {
if (a[i] != b[i]) { if (a[i] != b[i]) {
failed(i, "" + a[i], "" + b[i]); failedCompare(i, "" + a[i], "" + b[i]);
} }
} }
} }
...@@ -1042,23 +1043,46 @@ public class Sorting { ...@@ -1042,23 +1043,46 @@ public class Sorting {
private static void compare(double[] a, double[] b) { private static void compare(double[] a, double[] b) {
for (int i = 0; i < a.length; i++) { for (int i = 0; i < a.length; i++) {
if (a[i] != b[i]) { if (a[i] != b[i]) {
failed(i, "" + a[i], "" + b[i]); failedCompare(i, "" + a[i], "" + b[i]);
} }
} }
} }
private static void checkSorted(Integer[] a) { private static void compare(Integer[] a, Integer[] b) {
for (int i = 0; i < a.length - 1; i++) { for (int i = 0; i < a.length; i++) {
if (a[i].intValue() > a[i + 1].intValue()) { if (a[i].compareTo(b[i]) != 0) {
failed(i, "" + a[i], "" + a[i + 1]); failedCompare(i, "" + a[i], "" + b[i]);
} }
} }
} }
private static void checkSorted(Object object) {
if (object instanceof int[]) {
checkSorted((int[]) object);
} else if (object instanceof long[]) {
checkSorted((long[]) object);
} else if (object instanceof short[]) {
checkSorted((short[]) object);
} else if (object instanceof byte[]) {
checkSorted((byte[]) object);
} else if (object instanceof char[]) {
checkSorted((char[]) object);
} else if (object instanceof float[]) {
checkSorted((float[]) object);
} else if (object instanceof double[]) {
checkSorted((double[]) object);
} else if (object instanceof Integer[]) {
checkSorted((Integer[]) object);
} else {
failed("Unknow type of array: " + object + " of class " +
object.getClass().getName());
}
}
private static void checkSorted(int[] a) { private static void checkSorted(int[] a) {
for (int i = 0; i < a.length - 1; i++) { for (int i = 0; i < a.length - 1; i++) {
if (a[i] > a[i + 1]) { if (a[i] > a[i + 1]) {
failed(i, "" + a[i], "" + a[i + 1]); failedSort(i, "" + a[i], "" + a[i + 1]);
} }
} }
} }
...@@ -1066,7 +1090,7 @@ public class Sorting { ...@@ -1066,7 +1090,7 @@ public class Sorting {
private static void checkSorted(long[] a) { private static void checkSorted(long[] a) {
for (int i = 0; i < a.length - 1; i++) { for (int i = 0; i < a.length - 1; i++) {
if (a[i] > a[i + 1]) { if (a[i] > a[i + 1]) {
failed(i, "" + a[i], "" + a[i + 1]); failedSort(i, "" + a[i], "" + a[i + 1]);
} }
} }
} }
...@@ -1074,7 +1098,7 @@ public class Sorting { ...@@ -1074,7 +1098,7 @@ public class Sorting {
private static void checkSorted(short[] a) { private static void checkSorted(short[] a) {
for (int i = 0; i < a.length - 1; i++) { for (int i = 0; i < a.length - 1; i++) {
if (a[i] > a[i + 1]) { if (a[i] > a[i + 1]) {
failed(i, "" + a[i], "" + a[i + 1]); failedSort(i, "" + a[i], "" + a[i + 1]);
} }
} }
} }
...@@ -1082,7 +1106,7 @@ public class Sorting { ...@@ -1082,7 +1106,7 @@ public class Sorting {
private static void checkSorted(byte[] a) { private static void checkSorted(byte[] a) {
for (int i = 0; i < a.length - 1; i++) { for (int i = 0; i < a.length - 1; i++) {
if (a[i] > a[i + 1]) { if (a[i] > a[i + 1]) {
failed(i, "" + a[i], "" + a[i + 1]); failedSort(i, "" + a[i], "" + a[i + 1]);
} }
} }
} }
...@@ -1090,7 +1114,7 @@ public class Sorting { ...@@ -1090,7 +1114,7 @@ public class Sorting {
private static void checkSorted(char[] a) { private static void checkSorted(char[] a) {
for (int i = 0; i < a.length - 1; i++) { for (int i = 0; i < a.length - 1; i++) {
if (a[i] > a[i + 1]) { if (a[i] > a[i + 1]) {
failed(i, "" + a[i], "" + a[i + 1]); failedSort(i, "" + a[i], "" + a[i + 1]);
} }
} }
} }
...@@ -1098,7 +1122,7 @@ public class Sorting { ...@@ -1098,7 +1122,7 @@ public class Sorting {
private static void checkSorted(float[] a) { private static void checkSorted(float[] a) {
for (int i = 0; i < a.length - 1; i++) { for (int i = 0; i < a.length - 1; i++) {
if (a[i] > a[i + 1]) { if (a[i] > a[i + 1]) {
failed(i, "" + a[i], "" + a[i + 1]); failedSort(i, "" + a[i], "" + a[i + 1]);
} }
} }
} }
...@@ -1106,34 +1130,45 @@ public class Sorting { ...@@ -1106,34 +1130,45 @@ public class Sorting {
private static void checkSorted(double[] a) { private static void checkSorted(double[] a) {
for (int i = 0; i < a.length - 1; i++) { for (int i = 0; i < a.length - 1; i++) {
if (a[i] > a[i + 1]) { if (a[i] > a[i + 1]) {
failed(i, "" + a[i], "" + a[i + 1]); failedSort(i, "" + a[i], "" + a[i + 1]);
}
}
}
private static void checkSorted(Integer[] a) {
for (int i = 0; i < a.length - 1; i++) {
if (a[i].intValue() > a[i + 1].intValue()) {
failedSort(i, "" + a[i], "" + a[i + 1]);
} }
} }
} }
private static void checkCheckSum(Object test, Object golden) { private static void checkCheckSum(Object test, Object golden) {
if (checkSum(test) != checkSum(golden)) { if (checkSumXor(test) != checkSumXor(golden)) {
failed("It seems that original and sorted arrays are not identical"); failed("Original and sorted arrays are not identical [xor]");
}
if (checkSumPlus(test) != checkSumPlus(golden)) {
failed("Original and sorted arrays are not identical [plus]");
} }
} }
private static int checkSum(Object object) { private static int checkSumXor(Object object) {
if (object instanceof int[]) { if (object instanceof int[]) {
return checkSum((int[]) object); return checkSumXor((int[]) object);
} else if (object instanceof long[]) { } else if (object instanceof long[]) {
return checkSum((long[]) object); return checkSumXor((long[]) object);
} else if (object instanceof short[]) { } else if (object instanceof short[]) {
return checkSum((short[]) object); return checkSumXor((short[]) object);
} else if (object instanceof byte[]) { } else if (object instanceof byte[]) {
return checkSum((byte[]) object); return checkSumXor((byte[]) object);
} else if (object instanceof char[]) { } else if (object instanceof char[]) {
return checkSum((char[]) object); return checkSumXor((char[]) object);
} else if (object instanceof float[]) { } else if (object instanceof float[]) {
return checkSum((float[]) object); return checkSumXor((float[]) object);
} else if (object instanceof double[]) { } else if (object instanceof double[]) {
return checkSum((double[]) object); return checkSumXor((double[]) object);
} else if (object instanceof Integer[]) { } else if (object instanceof Integer[]) {
return checkSum((Integer[]) object); return checkSumXor((Integer[]) object);
} else { } else {
failed("Unknow type of array: " + object + " of class " + failed("Unknow type of array: " + object + " of class " +
object.getClass().getName()); object.getClass().getName());
...@@ -1141,76 +1176,275 @@ public class Sorting { ...@@ -1141,76 +1176,275 @@ public class Sorting {
} }
} }
private static int checkSum(Integer[] a) { private static int checkSumXor(Integer[] a) {
int checkXorSum = 0; int checkSum = 0;
for (Integer e : a) { for (Integer e : a) {
checkXorSum ^= e.intValue(); checkSum ^= e.intValue();
} }
return checkXorSum; return checkSum;
} }
private static int checkSum(int[] a) { private static int checkSumXor(int[] a) {
int checkXorSum = 0; int checkSum = 0;
for (int e : a) { for (int e : a) {
checkXorSum ^= e; checkSum ^= e;
} }
return checkXorSum; return checkSum;
} }
private static int checkSum(long[] a) { private static int checkSumXor(long[] a) {
long checkXorSum = 0; long checkSum = 0;
for (long e : a) { for (long e : a) {
checkXorSum ^= e; checkSum ^= e;
} }
return (int) checkXorSum; return (int) checkSum;
} }
private static int checkSum(short[] a) { private static int checkSumXor(short[] a) {
short checkXorSum = 0; short checkSum = 0;
for (short e : a) { for (short e : a) {
checkXorSum ^= e; checkSum ^= e;
} }
return (int) checkXorSum; return (int) checkSum;
} }
private static int checkSum(byte[] a) { private static int checkSumXor(byte[] a) {
byte checkXorSum = 0; byte checkSum = 0;
for (byte e : a) { for (byte e : a) {
checkXorSum ^= e; checkSum ^= e;
} }
return (int) checkXorSum; return (int) checkSum;
} }
private static int checkSum(char[] a) { private static int checkSumXor(char[] a) {
char checkXorSum = 0; char checkSum = 0;
for (char e : a) { for (char e : a) {
checkXorSum ^= e; checkSum ^= e;
} }
return (int) checkXorSum; return (int) checkSum;
} }
private static int checkSum(float[] a) { private static int checkSumXor(float[] a) {
int checkXorSum = 0; int checkSum = 0;
for (float e : a) { for (float e : a) {
checkXorSum ^= (int) e; checkSum ^= (int) e;
} }
return checkXorSum; return checkSum;
} }
private static int checkSum(double[] a) { private static int checkSumXor(double[] a) {
int checkXorSum = 0; int checkSum = 0;
for (double e : a) { for (double e : a) {
checkXorSum ^= (int) e; checkSum ^= (int) e;
}
return checkSum;
}
private static int checkSumPlus(Object object) {
if (object instanceof int[]) {
return checkSumPlus((int[]) object);
} else if (object instanceof long[]) {
return checkSumPlus((long[]) object);
} else if (object instanceof short[]) {
return checkSumPlus((short[]) object);
} else if (object instanceof byte[]) {
return checkSumPlus((byte[]) object);
} else if (object instanceof char[]) {
return checkSumPlus((char[]) object);
} else if (object instanceof float[]) {
return checkSumPlus((float[]) object);
} else if (object instanceof double[]) {
return checkSumPlus((double[]) object);
} else if (object instanceof Integer[]) {
return checkSumPlus((Integer[]) object);
} else {
failed("Unknow type of array: " + object + " of class " +
object.getClass().getName());
return -1;
}
}
private static int checkSumPlus(int[] a) {
int checkSum = 0;
for (int e : a) {
checkSum += e;
}
return checkSum;
}
private static int checkSumPlus(long[] a) {
long checkSum = 0;
for (long e : a) {
checkSum += e;
}
return (int) checkSum;
}
private static int checkSumPlus(short[] a) {
short checkSum = 0;
for (short e : a) {
checkSum += e;
}
return (int) checkSum;
}
private static int checkSumPlus(byte[] a) {
byte checkSum = 0;
for (byte e : a) {
checkSum += e;
}
return (int) checkSum;
}
private static int checkSumPlus(char[] a) {
char checkSum = 0;
for (char e : a) {
checkSum += e;
}
return (int) checkSum;
}
private static int checkSumPlus(float[] a) {
int checkSum = 0;
for (float e : a) {
checkSum += (int) e;
}
return checkSum;
}
private static int checkSumPlus(double[] a) {
int checkSum = 0;
for (double e : a) {
checkSum += (int) e;
}
return checkSum;
}
private static int checkSumPlus(Integer[] a) {
int checkSum = 0;
for (Integer e : a) {
checkSum += e.intValue();
}
return checkSum;
}
private static void sortByInsertionSort(Object object) {
if (object instanceof int[]) {
sortByInsertionSort((int[]) object);
} else if (object instanceof long[]) {
sortByInsertionSort((long[]) object);
} else if (object instanceof short[]) {
sortByInsertionSort((short[]) object);
} else if (object instanceof byte[]) {
sortByInsertionSort((byte[]) object);
} else if (object instanceof char[]) {
sortByInsertionSort((char[]) object);
} else if (object instanceof float[]) {
sortByInsertionSort((float[]) object);
} else if (object instanceof double[]) {
sortByInsertionSort((double[]) object);
} else if (object instanceof Integer[]) {
sortByInsertionSort((Integer[]) object);
} else {
failed("Unknow type of array: " + object + " of class " +
object.getClass().getName());
}
}
private static void sortByInsertionSort(int[] a) {
for (int j, i = 1; i < a.length; i++) {
int ai = a[i];
for (j = i - 1; j >= 0 && ai < a[j]; j--) {
a[j + 1] = a[j];
}
a[j + 1] = ai;
}
}
private static void sortByInsertionSort(long[] a) {
for (int j, i = 1; i < a.length; i++) {
long ai = a[i];
for (j = i - 1; j >= 0 && ai < a[j]; j--) {
a[j + 1] = a[j];
}
a[j + 1] = ai;
}
}
private static void sortByInsertionSort(short[] a) {
for (int j, i = 1; i < a.length; i++) {
short ai = a[i];
for (j = i - 1; j >= 0 && ai < a[j]; j--) {
a[j + 1] = a[j];
}
a[j + 1] = ai;
}
}
private static void sortByInsertionSort(byte[] a) {
for (int j, i = 1; i < a.length; i++) {
byte ai = a[i];
for (j = i - 1; j >= 0 && ai < a[j]; j--) {
a[j + 1] = a[j];
}
a[j + 1] = ai;
}
}
private static void sortByInsertionSort(char[] a) {
for (int j, i = 1; i < a.length; i++) {
char ai = a[i];
for (j = i - 1; j >= 0 && ai < a[j]; j--) {
a[j + 1] = a[j];
}
a[j + 1] = ai;
}
}
private static void sortByInsertionSort(float[] a) {
for (int j, i = 1; i < a.length; i++) {
float ai = a[i];
for (j = i - 1; j >= 0 && ai < a[j]; j--) {
a[j + 1] = a[j];
}
a[j + 1] = ai;
}
}
private static void sortByInsertionSort(double[] a) {
for (int j, i = 1; i < a.length; i++) {
double ai = a[i];
for (j = i - 1; j >= 0 && ai < a[j]; j--) {
a[j + 1] = a[j];
}
a[j + 1] = ai;
}
}
private static void sortByInsertionSort(Integer[] a) {
for (int j, i = 1; i < a.length; i++) {
Integer ai = a[i];
for (j = i - 1; j >= 0 && ai < a[j]; j--) {
a[j + 1] = a[j];
}
a[j + 1] = ai;
} }
return checkXorSum;
} }
private static void sort(Object object) { private static void sort(Object object) {
...@@ -1292,7 +1526,7 @@ public class Sorting { ...@@ -1292,7 +1526,7 @@ public class Sorting {
for (int i = fromIndex; i < toIndex - 1; i++) { for (int i = fromIndex; i < toIndex - 1; i++) {
if (a[i].intValue() > a[i + 1].intValue()) { if (a[i].intValue() > a[i + 1].intValue()) {
failed(i, "" + a[i], "" + a[i + 1]); failedSort(i, "" + a[i], "" + a[i + 1]);
} }
} }
...@@ -1314,7 +1548,7 @@ public class Sorting { ...@@ -1314,7 +1548,7 @@ public class Sorting {
for (int i = fromIndex; i < toIndex - 1; i++) { for (int i = fromIndex; i < toIndex - 1; i++) {
if (a[i] > a[i + 1]) { if (a[i] > a[i + 1]) {
failed(i, "" + a[i], "" + a[i + 1]); failedSort(i, "" + a[i], "" + a[i + 1]);
} }
} }
...@@ -1336,7 +1570,7 @@ public class Sorting { ...@@ -1336,7 +1570,7 @@ public class Sorting {
for (int i = fromIndex; i < toIndex - 1; i++) { for (int i = fromIndex; i < toIndex - 1; i++) {
if (a[i] > a[i + 1]) { if (a[i] > a[i + 1]) {
failed(i, "" + a[i], "" + a[i + 1]); failedSort(i, "" + a[i], "" + a[i + 1]);
} }
} }
...@@ -1358,7 +1592,7 @@ public class Sorting { ...@@ -1358,7 +1592,7 @@ public class Sorting {
for (int i = fromIndex; i < toIndex - 1; i++) { for (int i = fromIndex; i < toIndex - 1; i++) {
if (a[i] > a[i + 1]) { if (a[i] > a[i + 1]) {
failed(i, "" + a[i], "" + a[i + 1]); failedSort(i, "" + a[i], "" + a[i + 1]);
} }
} }
...@@ -1380,7 +1614,7 @@ public class Sorting { ...@@ -1380,7 +1614,7 @@ public class Sorting {
for (int i = fromIndex; i < toIndex - 1; i++) { for (int i = fromIndex; i < toIndex - 1; i++) {
if (a[i] > a[i + 1]) { if (a[i] > a[i + 1]) {
failed(i, "" + a[i], "" + a[i + 1]); failedSort(i, "" + a[i], "" + a[i + 1]);
} }
} }
...@@ -1402,7 +1636,7 @@ public class Sorting { ...@@ -1402,7 +1636,7 @@ public class Sorting {
for (int i = fromIndex; i < toIndex - 1; i++) { for (int i = fromIndex; i < toIndex - 1; i++) {
if (a[i] > a[i + 1]) { if (a[i] > a[i + 1]) {
failed(i, "" + a[i], "" + a[i + 1]); failedSort(i, "" + a[i], "" + a[i + 1]);
} }
} }
...@@ -1424,7 +1658,7 @@ public class Sorting { ...@@ -1424,7 +1658,7 @@ public class Sorting {
for (int i = fromIndex; i < toIndex - 1; i++) { for (int i = fromIndex; i < toIndex - 1; i++) {
if (a[i] > a[i + 1]) { if (a[i] > a[i + 1]) {
failed(i, "" + a[i], "" + a[i + 1]); failedSort(i, "" + a[i], "" + a[i + 1]);
} }
} }
...@@ -1446,7 +1680,7 @@ public class Sorting { ...@@ -1446,7 +1680,7 @@ public class Sorting {
for (int i = fromIndex; i < toIndex - 1; i++) { for (int i = fromIndex; i < toIndex - 1; i++) {
if (a[i] > a[i + 1]) { if (a[i] > a[i + 1]) {
failed(i, "" + a[i], "" + a[i + 1]); failedSort(i, "" + a[i], "" + a[i + 1]);
} }
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册