--- a/jdk/src/share/classes/java/util/DualPivotQuicksort.java Thu Oct 14 18:01:47 2010 -0700
+++ b/jdk/src/share/classes/java/util/DualPivotQuicksort.java Fri Oct 15 12:10:32 2010 +0100
@@ -36,7 +36,7 @@
* @author Jon Bentley
* @author Josh Bloch
*
- * @version 2010.06.21 m765.827.12i:5\7
+ * @version 2010.10.13 m765.827.12i:5\7p
* @since 1.7
*/
final class DualPivotQuicksort {
@@ -54,26 +54,26 @@
* If the length of an array to be sorted is less than this
* 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
- * this constant, counting sort is used in preference to Quicksort.
+ * If the length of a byte array to be sorted is greater than this
+ * 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
* 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.
*/
/**
- * Sorts the specified array into ascending numerical order.
+ * Sorts the specified array.
*
* @param a the array to be sorted
*/
@@ -82,58 +82,34 @@
}
/**
- * 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(int[] a, int fromIndex, int toIndex) {
- rangeCheck(a.length, fromIndex, toIndex);
- sort(a, fromIndex, toIndex - 1, true);
- }
-
- /**
- * 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.
+ * Sorts the specified range of the array.
*
* @param a the array to be sorted
* @param left the index of the first element, inclusive, to be sorted
* @param right the index of the last element, inclusive, to be sorted
- * @param leftmost indicates if the part is the most left in the range
+ */
+ public static void sort(int[] a, int left, int right) {
+ sort(a, left, right, true);
+ }
+
+ /**
+ * Sorts the specified range of the array by Dual-Pivot Quicksort.
+ *
+ * @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 this part is the leftmost in the range
*/
private static void sort(int[] a, int left, int right, boolean leftmost) {
int length = right - left + 1;
- // Use insertion sort on tiny arrays
+ // Use insertion sort on small arrays
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++) {
- 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.
+ * Traditional (without sentinel) insertion sort,
+ * optimized for server VM, is used in case of
+ * the leftmost part.
*/
for (int i = left, j = i; i < right; j = ++i) {
int ai = a[i + 1];
@@ -145,12 +121,54 @@
}
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;
}
// 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
@@ -232,10 +250,14 @@
* Pointer k is the first index of ?-part.
*/
outer:
- for (int k = less; k <= great; k++) {
+ for (int k = less - 1; ++k <= great; ) {
int ak = a[k];
if (ak < pivot1) { // Move a[k] to left part
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;
less++;
} else if (ak > pivot2) { // Move a[k] to right part
@@ -244,13 +266,17 @@
break outer;
}
}
- if (a[great] < pivot1) {
+ if (a[great] < pivot1) { // a[great] <= pivot2
a[k] = a[less];
a[less] = a[great];
less++;
} else { // pivot1 <= a[great] <= pivot2
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;
great--;
}
@@ -265,7 +291,7 @@
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.
*/
if (less < e1 && e5 < great) {
@@ -299,7 +325,7 @@
* Pointer k is the first index of ?-part.
*/
outer:
- for (int k = less; k <= great; k++) {
+ for (int k = less - 1; ++k <= great; ) {
int ak = a[k];
if (ak == pivot1) { // Move a[k] to left part
a[k] = a[less];
@@ -311,7 +337,7 @@
break outer;
}
}
- if (a[great] == pivot1) {
+ if (a[great] == pivot1) { // a[great] < pivot2
a[k] = a[less];
/*
* Even though a[great] equals to pivot1, the
@@ -337,7 +363,7 @@
} else { // Pivots are equal
/*
- * Partition degenerates to the traditional 3-way
+ * Partitioning degenerates to the traditional 3-way
* (or "Dutch National Flag") schema:
*
* left part center part right part
@@ -356,28 +382,20 @@
*
* 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) {
continue;
}
int 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) {
+ if (a[great] < pivot1) { // a[great] <= pivot1
a[k] = a[less];
a[less] = a[great];
less++;
@@ -397,14 +415,18 @@
}
}
- // 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, great + 1, right, false);
}
}
/**
- * Sorts the specified array into ascending numerical order.
+ * Sorts the specified array.
*
* @param a the array to be sorted
*/
@@ -413,58 +435,34 @@
}
/**
- * 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(long[] a, int fromIndex, int toIndex) {
- rangeCheck(a.length, fromIndex, toIndex);
- sort(a, fromIndex, toIndex - 1, true);
- }
-
- /**
- * 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.
+ * Sorts the specified range of the array.
*
* @param a the array to be sorted
* @param left the index of the first element, inclusive, to be sorted
* @param right the index of the last element, inclusive, to be sorted
- * @param leftmost indicates if the part is the most left in the range
+ */
+ public static void sort(long[] a, int left, int right) {
+ sort(a, left, right, true);
+ }
+
+ /**
+ * Sorts the specified range of the array by Dual-Pivot Quicksort.
+ *
+ * @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 this part is the leftmost in the range
*/
private static void sort(long[] a, int left, int right, boolean leftmost) {
int length = right - left + 1;
- // Use insertion sort on tiny arrays
+ // Use insertion sort on small arrays
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)
- * insertion sort, optimized for server JVM, is used.
+ * Traditional (without sentinel) insertion sort,
+ * optimized for server VM, is used in case of
+ * the leftmost part.
*/
for (int i = left, j = i; i < right; j = ++i) {
long ai = a[i + 1];
@@ -476,12 +474,54 @@
}
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; ) {
+ long 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;
+ }
+ long last = a[right];
+
+ while (last < a[--right]) {
+ a[right + 1] = a[right];
+ }
+ a[right + 1] = last;
}
return;
}
// 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
@@ -563,10 +603,14 @@
* Pointer k is the first index of ?-part.
*/
outer:
- for (int k = less; k <= great; k++) {
+ for (int k = less - 1; ++k <= great; ) {
long ak = a[k];
if (ak < pivot1) { // Move a[k] to left part
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;
less++;
} else if (ak > pivot2) { // Move a[k] to right part
@@ -575,13 +619,17 @@
break outer;
}
}
- if (a[great] < pivot1) {
+ if (a[great] < pivot1) { // a[great] <= pivot2
a[k] = a[less];
a[less] = a[great];
less++;
} else { // pivot1 <= a[great] <= pivot2
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;
great--;
}
@@ -596,7 +644,7 @@
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.
*/
if (less < e1 && e5 < great) {
@@ -630,7 +678,7 @@
* Pointer k is the first index of ?-part.
*/
outer:
- for (int k = less; k <= great; k++) {
+ for (int k = less - 1; ++k <= great; ) {
long ak = a[k];
if (ak == pivot1) { // Move a[k] to left part
a[k] = a[less];
@@ -642,7 +690,7 @@
break outer;
}
}
- if (a[great] == pivot1) {
+ if (a[great] == pivot1) { // a[great] < pivot2
a[k] = a[less];
/*
* Even though a[great] equals to pivot1, the
@@ -668,7 +716,7 @@
} else { // Pivots are equal
/*
- * Partition degenerates to the traditional 3-way
+ * Partitioning degenerates to the traditional 3-way
* (or "Dutch National Flag") schema:
*
* left part center part right part
@@ -687,28 +735,20 @@
*
* 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) {
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) {
+ if (a[great] < pivot1) { // a[great] <= pivot1
a[k] = a[less];
a[less] = a[great];
less++;
@@ -728,45 +768,51 @@
}
}
- // 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, 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(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);
- }
+ 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).
+ * Sorts the specified range of the array.
*
* @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}
+ * @param left the index of the first element, inclusive, to be sorted
+ * @param right the index of the last element, inclusive, to be sorted
*/
- public static void sort(short[] a, int fromIndex, int toIndex) {
- rangeCheck(a.length, fromIndex, toIndex);
+ public static void sort(short[] a, int left, int right) {
+ // Use counting sort on large arrays
+ if (right - left > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) {
+ int[] count = new int[NUM_SHORT_VALUES];
- if (toIndex - fromIndex > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) {
- countingSort(a, fromIndex, toIndex - 1);
- } else {
- sort(a, fromIndex, toIndex - 1, true);
+ for (int i = left - 1; ++i <= right; ) {
+ count[a[i] - Short.MIN_VALUE]++;
+ }
+ for (int i = NUM_SHORT_VALUES, k = right + 1; k > left; ) {
+ while (count[--i] == 0);
+ short value = (short) (i + Short.MIN_VALUE);
+ int s = count[i];
+
+ do {
+ a[--k] = value;
+ } while (--s > 0);
+ }
+ } else { // Use Dual-Pivot Quicksort on small arrays
+ sort(a, left, right, true);
}
}
@@ -774,66 +820,23 @@
private static final int NUM_SHORT_VALUES = 1 << 16;
/**
- * Sorts the specified range of the array by counting sort.
+ * Sorts the specified range of the array by Dual-Pivot Quicksort.
*
* @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
+ * @param leftmost indicates if this part is the leftmost 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
+ // Use insertion sort on small arrays
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++) {
- short 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.
+ * Traditional (without sentinel) insertion sort,
+ * optimized for server VM, is used in case of
+ * the leftmost part.
*/
for (int i = left, j = i; i < right; j = ++i) {
short ai = a[i + 1];
@@ -845,12 +848,54 @@
}
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;
}
// 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
@@ -932,10 +977,14 @@
* Pointer k is the first index of ?-part.
*/
outer:
- for (int k = less; k <= great; k++) {
+ for (int k = less - 1; ++k <= great; ) {
short ak = a[k];
if (ak < pivot1) { // Move a[k] to left part
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;
less++;
} else if (ak > pivot2) { // Move a[k] to right part
@@ -944,13 +993,17 @@
break outer;
}
}
- if (a[great] < pivot1) {
+ if (a[great] < pivot1) { // a[great] <= pivot2
a[k] = a[less];
a[less] = a[great];
less++;
} else { // pivot1 <= a[great] <= pivot2
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;
great--;
}
@@ -965,7 +1018,7 @@
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.
*/
if (less < e1 && e5 < great) {
@@ -999,7 +1052,7 @@
* Pointer k is the first index of ?-part.
*/
outer:
- for (int k = less; k <= great; k++) {
+ for (int k = less - 1; ++k <= great; ) {
short ak = a[k];
if (ak == pivot1) { // Move a[k] to left part
a[k] = a[less];
@@ -1011,7 +1064,7 @@
break outer;
}
}
- if (a[great] == pivot1) {
+ if (a[great] == pivot1) { // a[great] < pivot2
a[k] = a[less];
/*
* Even though a[great] equals to pivot1, the
@@ -1037,7 +1090,7 @@
} else { // Pivots are equal
/*
- * Partition degenerates to the traditional 3-way
+ * Partitioning degenerates to the traditional 3-way
* (or "Dutch National Flag") schema:
*
* left part center part right part
@@ -1056,28 +1109,20 @@
*
* 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) {
continue;
}
short 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) {
+ if (a[great] < pivot1) { // a[great] <= pivot1
a[k] = a[less];
a[less] = a[great];
less++;
@@ -1097,45 +1142,51 @@
}
}
- // 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, 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);
- }
+ 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).
+ * Sorts the specified range of the array.
*
* @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}
+ * @param left the index of the first element, inclusive, to be sorted
+ * @param right the index of the last element, inclusive, to be sorted
*/
- public static void sort(char[] a, int fromIndex, int toIndex) {
- rangeCheck(a.length, fromIndex, toIndex);
+ public static void sort(char[] a, int left, int right) {
+ // Use counting sort on large arrays
+ if (right - left > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) {
+ int[] count = new int[NUM_CHAR_VALUES];
- if (toIndex - fromIndex > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) {
- countingSort(a, fromIndex, toIndex - 1);
- } else {
- sort(a, fromIndex, toIndex - 1, true);
+ for (int i = left - 1; ++i <= right; ) {
+ count[a[i]]++;
+ }
+ for (int i = NUM_CHAR_VALUES, k = right + 1; k > left; ) {
+ while (count[--i] == 0);
+ char value = (char) i;
+ int s = count[i];
+
+ do {
+ a[--k] = value;
+ } while (--s > 0);
+ }
+ } else { // Use Dual-Pivot Quicksort on small arrays
+ sort(a, left, right, true);
}
}
@@ -1143,66 +1194,23 @@
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 by Dual-Pivot Quicksort.
*
* @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(char[] a, int left, int right) {
- int[] count = new int[NUM_CHAR_VALUES];
-
- for (int i = left; i <= right; i++) {
- count[a[i]]++;
- }
- for (int i = 0, k = left; k <= right; i++) {
- while (count[i] == 0) {
- i++;
- }
- char value = (char) i;
- 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
+ * @param leftmost indicates if this part is the leftmost in the range
*/
private static void sort(char[] a, int left, int right, boolean leftmost) {
int length = right - left + 1;
- // Use insertion sort on tiny arrays
+ // Use insertion sort on small arrays
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)
- * insertion sort, optimized for server JVM, is used.
+ * Traditional (without sentinel) insertion sort,
+ * optimized for server VM, is used in case of
+ * the leftmost part.
*/
for (int i = left, j = i; i < right; j = ++i) {
char ai = a[i + 1];
@@ -1214,12 +1222,54 @@
}
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;
}
// 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
@@ -1301,10 +1351,14 @@
* Pointer k is the first index of ?-part.
*/
outer:
- for (int k = less; k <= great; k++) {
+ for (int k = less - 1; ++k <= great; ) {
char ak = a[k];
if (ak < pivot1) { // Move a[k] to left part
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;
less++;
} else if (ak > pivot2) { // Move a[k] to right part
@@ -1313,13 +1367,17 @@
break outer;
}
}
- if (a[great] < pivot1) {
+ if (a[great] < pivot1) { // a[great] <= pivot2
a[k] = a[less];
a[less] = a[great];
less++;
} else { // pivot1 <= a[great] <= pivot2
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;
great--;
}
@@ -1334,7 +1392,7 @@
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.
*/
if (less < e1 && e5 < great) {
@@ -1368,7 +1426,7 @@
* Pointer k is the first index of ?-part.
*/
outer:
- for (int k = less; k <= great; k++) {
+ for (int k = less - 1; ++k <= great; ) {
char ak = a[k];
if (ak == pivot1) { // Move a[k] to left part
a[k] = a[less];
@@ -1380,7 +1438,7 @@
break outer;
}
}
- if (a[great] == pivot1) {
+ if (a[great] == pivot1) { // a[great] < pivot2
a[k] = a[less];
/*
* Even though a[great] equals to pivot1, the
@@ -1406,7 +1464,7 @@
} else { // Pivots are equal
/*
- * Partition degenerates to the traditional 3-way
+ * Partitioning degenerates to the traditional 3-way
* (or "Dutch National Flag") schema:
*
* left part center part right part
@@ -1425,28 +1483,20 @@
*
* 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) {
continue;
}
char 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) {
+ if (a[great] < pivot1) { // a[great] <= pivot1
a[k] = a[less];
a[less] = a[great];
less++;
@@ -1466,442 +1516,90 @@
}
}
- // 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, great + 1, right, false);
}
}
- /**
- * Sorts the specified array into ascending numerical order.
- *
- * @param a the array to be sorted
- */
- public static void sort(byte[] a) {
- if (a.length > COUNTING_SORT_THRESHOLD_FOR_BYTE) {
- 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 array.
+ *
+ * @param a the array to be sorted
+ */
+ public static void sort(byte[] a) {
+ sort(a, 0, a.length - 1);
+ }
+
+ /**
+ * Sorts the specified range of the array.
*
* @param a the array to be sorted
* @param left the index of the first element, inclusive, to be sorted
* @param right the index of the last element, inclusive, to be sorted
*/
- private static void countingSort(byte[] a, int left, int right) {
- int[] count = new int[NUM_BYTE_VALUES];
+ public static void sort(byte[] a, int left, int right) {
+ // Use counting sort on large arrays
+ 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];
- for (int i = left; i <= right; i++) {
- count[a[i] - Byte.MIN_VALUE]++;
- }
- for (int i = NUM_BYTE_VALUES - 1, k = right; k >= left; i--) {
- while (count[i] == 0) {
- i--;
+ do {
+ a[--k] = value;
+ } while (--s > 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 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(byte[] 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++) {
- 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)
- * insertion sort, optimized for server JVM, is used.
- */
- 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;
- }
- }
- 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]) { byte 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 (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 (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]) { byte 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.
- */
- byte pivot1 = a[e2];
- byte 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++) {
- byte 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.
- */
- while (a[less] == pivot1) {
- less++;
- }
- while (a[great] == pivot2) {
- great--;
- }
-
- /*
- * Partitioning:
- *
- * left part center part right part
- * +----------------------------------------------------------+
- * | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 |
- * +----------------------------------------------------------+
- * ^ ^ ^
- * | | |
- * 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 = less; k <= great; k++) {
- byte 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
- sort(a, less, great, false);
-
- } else { // Pivots are equal
- /*
- * 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;
- }
- byte 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) {
- a[k] = a[less];
- 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;
- great--;
- }
- }
-
- // Sort left and right parts recursively
- sort(a, left, less - 1, leftmost);
- sort(a, great + 1, right, false);
- }
- }
-
- /**
- * Sorts the specified array into ascending numerical order.
- *
- * <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.
+ * Sorts the specified array.
*
* @param a the array to be sorted
*/
public static void sort(float[] 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 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 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) {
- rangeCheck(a.length, fromIndex, toIndex);
- sortNegZeroAndNaN(a, fromIndex, toIndex - 1);
- }
-
- /**
- * Sorts the specified range of the array into ascending order. The
- * 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}.
+ * Sorts the specified range of the array.
*
* @param a the array to be sorted
* @param left the index of the first element, inclusive, to be sorted
* @param right the index of the last element, inclusive, to be sorted
*/
- private static void 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.
*/
while (left <= right && Float.isNaN(a[right])) {
right--;
}
- for (int k = right - 1; k >= left; k--) {
+ for (int k = right; --k >= left; ) {
float ak = a[k];
if (ak != ak) { // a[k] is NaN
a[k] = a[right];
@@ -1921,7 +1619,7 @@
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) {
int middle = (left + hi) >>> 1;
@@ -1946,12 +1644,12 @@
*
* Partitioning:
*
- * +---------------------------------------------------+
- * | < 0.0 | -0.0 | 0.0 | ? ( >= 0.0 ) |
- * +---------------------------------------------------+
- * ^ ^ ^
- * | | |
- * left p k
+ * +----------------------------------------------------+
+ * | < 0.0 | -0.0 | 0.0 | ? ( >= 0.0 ) |
+ * +----------------------------------------------------+
+ * ^ ^ ^
+ * | | |
+ * left p k
*
* Invariants:
*
@@ -1962,53 +1660,36 @@
*
* 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];
if (ak != 0.0f) {
break;
}
if (Float.floatToRawIntBits(ak) < 0) { // ak is -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
- * 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.
+ * Sorts the specified range of the array by Dual-Pivot Quicksort.
*
* @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
+ * @param leftmost indicates if this part is the leftmost in the range
*/
private static void sort(float[] a, int left, int right,boolean leftmost) {
int length = right - left + 1;
- // Use insertion sort on tiny arrays
+ // Use insertion sort on small arrays
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)
- * insertion sort, optimized for server JVM, is used.
+ * Traditional (without sentinel) insertion sort,
+ * optimized for server VM, is used in case of
+ * the leftmost part.
*/
for (int i = left, j = i; i < right; j = ++i) {
float ai = a[i + 1];
@@ -2020,12 +1701,54 @@
}
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;
}
// 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
@@ -2107,10 +1830,14 @@
* Pointer k is the first index of ?-part.
*/
outer:
- for (int k = less; k <= great; k++) {
+ for (int k = less - 1; ++k <= great; ) {
float ak = a[k];
if (ak < pivot1) { // Move a[k] to left part
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;
less++;
} else if (ak > pivot2) { // Move a[k] to right part
@@ -2119,13 +1846,17 @@
break outer;
}
}
- if (a[great] < pivot1) {
+ if (a[great] < pivot1) { // a[great] <= pivot2
a[k] = a[less];
a[less] = a[great];
less++;
} else { // pivot1 <= a[great] <= pivot2
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;
great--;
}
@@ -2140,7 +1871,7 @@
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.
*/
if (less < e1 && e5 < great) {
@@ -2174,7 +1905,7 @@
* Pointer k is the first index of ?-part.
*/
outer:
- for (int k = less; k <= great; k++) {
+ for (int k = less - 1; ++k <= great; ) {
float ak = a[k];
if (ak == pivot1) { // Move a[k] to left part
a[k] = a[less];
@@ -2186,7 +1917,7 @@
break outer;
}
}
- if (a[great] == pivot1) {
+ if (a[great] == pivot1) { // a[great] < pivot2
a[k] = a[less];
/*
* Even though a[great] equals to pivot1, the
@@ -2212,7 +1943,7 @@
} else { // Pivots are equal
/*
- * Partition degenerates to the traditional 3-way
+ * Partitioning degenerates to the traditional 3-way
* (or "Dutch National Flag") schema:
*
* left part center part right part
@@ -2231,28 +1962,20 @@
*
* 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) {
continue;
}
float 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) {
+ if (a[great] < pivot1) { // a[great] <= pivot1
a[k] = a[less];
a[less] = a[great];
less++;
@@ -2272,73 +1995,40 @@
}
}
- // 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, great + 1, right, false);
}
}
/**
- * Sorts the specified array into ascending numerical order.
- *
- * <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.
+ * Sorts the specified array.
*
* @param a the array to be sorted
*/
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
- * 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}.
+ * Sorts the specified range of the array.
*
* @param a the array to be sorted
* @param left the index of the first element, inclusive, to be sorted
* @param right the index of the last element, inclusive, to be sorted
*/
- private static void 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.
*/
while (left <= right && Double.isNaN(a[right])) {
right--;
}
- for (int k = right - 1; k >= left; k--) {
+ for (int k = right; --k >= left; ) {
double ak = a[k];
if (ak != ak) { // a[k] is NaN
a[k] = a[right];
@@ -2358,7 +2048,7 @@
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) {
int middle = (left + hi) >>> 1;
@@ -2383,12 +2073,12 @@
*
* Partitioning:
*
- * +---------------------------------------------------+
- * | < 0.0 | -0.0 | 0.0 | ? ( >= 0.0 ) |
- * +---------------------------------------------------+
- * ^ ^ ^
- * | | |
- * left p k
+ * +----------------------------------------------------+
+ * | < 0.0 | -0.0 | 0.0 | ? ( >= 0.0 ) |
+ * +----------------------------------------------------+
+ * ^ ^ ^
+ * | | |
+ * left p k
*
* Invariants:
*
@@ -2399,53 +2089,36 @@
*
* 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];
if (ak != 0.0d) {
break;
}
if (Double.doubleToRawLongBits(ak) < 0) { // ak is -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
- * 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.
+ * Sorts the specified range of the array by Dual-Pivot Quicksort.
*
* @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
+ * @param leftmost indicates if this part is the leftmost in the range
*/
private static void sort(double[] a, int left,int right,boolean leftmost) {
int length = right - left + 1;
- // Use insertion sort on tiny arrays
+ // Use insertion sort on small arrays
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)
- * insertion sort, optimized for server JVM, is used.
+ * Traditional (without sentinel) insertion sort,
+ * optimized for server VM, is used in case of
+ * the leftmost part.
*/
for (int i = left, j = i; i < right; j = ++i) {
double ai = a[i + 1];
@@ -2457,12 +2130,54 @@
}
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;
}
// 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
@@ -2544,10 +2259,14 @@
* Pointer k is the first index of ?-part.
*/
outer:
- for (int k = less; k <= great; k++) {
+ for (int k = less - 1; ++k <= great; ) {
double ak = a[k];
if (ak < pivot1) { // Move a[k] to left part
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;
less++;
} else if (ak > pivot2) { // Move a[k] to right part
@@ -2556,13 +2275,17 @@
break outer;
}
}
- if (a[great] < pivot1) {
+ if (a[great] < pivot1) { // a[great] <= pivot2
a[k] = a[less];
a[less] = a[great];
less++;
} else { // pivot1 <= a[great] <= pivot2
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;
great--;
}
@@ -2577,7 +2300,7 @@
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.
*/
if (less < e1 && e5 < great) {
@@ -2611,7 +2334,7 @@
* Pointer k is the first index of ?-part.
*/
outer:
- for (int k = less; k <= great; k++) {
+ for (int k = less - 1; ++k <= great; ) {
double ak = a[k];
if (ak == pivot1) { // Move a[k] to left part
a[k] = a[less];
@@ -2623,7 +2346,7 @@
break outer;
}
}
- if (a[great] == pivot1) {
+ if (a[great] == pivot1) { // a[great] < pivot2
a[k] = a[less];
/*
* Even though a[great] equals to pivot1, the
@@ -2649,7 +2372,7 @@
} else { // Pivots are equal
/*
- * Partition degenerates to the traditional 3-way
+ * Partitioning degenerates to the traditional 3-way
* (or "Dutch National Flag") schema:
*
* left part center part right part
@@ -2668,28 +2391,20 @@
*
* 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) {
continue;
}
double 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) {
+ if (a[great] < pivot1) { // a[great] <= pivot1
a[k] = a[less];
a[less] = a[great];
less++;
@@ -2709,26 +2424,13 @@
}
}
- // 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, 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);
- }
- }
}
--- a/jdk/test/java/util/Arrays/Sorting.java Thu Oct 14 18:01:47 2010 -0700
+++ b/jdk/test/java/util/Arrays/Sorting.java Fri Oct 15 12:10:32 2010 +0100
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 6880672 6896573 6899694
+ * @bug 6880672 6896573 6899694 6976036
* @summary Exercise Arrays.sort
* @build Sorting
* @run main Sorting -shortrun
@@ -50,10 +50,10 @@
1, 2, 3, 21, 55, 1000, 10000 };
// 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
- private static final long[] SHORT_RUN_RANDOMS = {666};
+ private static final long[] SHORT_RUN_RANDOMS = { 666 };
public static void main(String[] args) {
boolean shortRun = args.length > 0 && args[0].equals("-shortrun");
@@ -82,6 +82,11 @@
reset(random);
for (int length : lengths) {
+ testAndCheckWithInsertionSort(length, random);
+ }
+ reset(random);
+
+ for (int length : lengths) {
testAndCheckWithCheckSum(length, random);
}
reset(random);
@@ -268,9 +273,7 @@
" length = " + length + ", m = " + m);
Object convertedGolden = converter.convert(golden);
Object convertedTest = converter.convert(test);
- // outArray(test);
sortSubArray(convertedTest, fromIndex, toIndex);
- // outArray(test);
checkSubArray(convertedTest, fromIndex, toIndex, m);
}
}
@@ -311,7 +314,7 @@
private static void checkSorted(Pair[] a) {
for (int i = 0; i < a.length - 1; i++) {
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 @@
int value4 = a[i++].getValue();
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);
}
if (!(value1 < value2 && value2 < value3 && value3 < value4)) {
@@ -385,6 +388,35 @@
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) {
ourDescription = "Check sorting with check sum";
int[] golden = new int[length];
@@ -460,9 +492,7 @@
builder.build(golden, a, g, z, n, p);
float[] test = golden.clone();
scramble(test);
- // outArray(test);
sort(test);
- // outArray(test);
compare(test, golden, a, n, g);
}
newLine = true;
@@ -500,9 +530,7 @@
builder.build(golden, a, g, z, n, p);
double[] test = golden.clone();
scramble(test);
- // outArray(test);
sort(test);
- // outArray(test);
compare(test, golden, a, n, g);
}
newLine = true;
@@ -721,12 +749,12 @@
for (int i = numNeg; i < numNeg + numNegZero; 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++) {
if (a[i] != b[i]) {
- failed(i, "" + a[i], "" + b[i]);
+ failedCompare(i, "" + a[i], "" + b[i]);
}
}
}
@@ -747,12 +775,12 @@
for (int i = numNeg; i < numNeg + numNegZero; 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++) {
if (a[i] != b[i]) {
- failed(i, "" + a[i], "" + b[i]);
+ failedCompare(i, "" + a[i], "" + b[i]);
}
}
}
@@ -841,8 +869,8 @@
int incCount = 1;
int decCount = a.length;
int i = 0;
- int period = m;
- m--;
+ int period = m--;
+
while (true) {
for (int k = 1; k <= period; k++) {
if (i >= a.length) {
@@ -922,6 +950,25 @@
}
}
+ 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) {
if (test instanceof int[]) {
compare((int[]) test, (int[]) golden);
@@ -945,19 +992,68 @@
}
}
- private static void checkWithCheckSum(Object test, Object golden) {
- checkSorted(test);
- checkCheckSum(test, golden);
+ private static void compare(int[] a, int[] b) {
+ for (int i = 0; i < a.length; i++) {
+ if (a[i] != b[i]) {
+ failedCompare(i, "" + a[i], "" + b[i]);
+ }
+ }
+ }
+
+ private static void compare(long[] a, long[] b) {
+ for (int i = 0; i < a.length; i++) {
+ if (a[i] != b[i]) {
+ failedCompare(i, "" + a[i], "" + b[i]);
+ }
+ }
+ }
+
+ private static void compare(short[] a, short[] b) {
+ for (int i = 0; i < a.length; i++) {
+ if (a[i] != b[i]) {
+ failedCompare(i, "" + a[i], "" + b[i]);
+ }
+ }
}
- 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 compare(byte[] a, byte[] b) {
+ for (int i = 0; i < a.length; i++) {
+ if (a[i] != b[i]) {
+ failedCompare(i, "" + a[i], "" + b[i]);
+ }
+ }
+ }
+
+ private static void compare(char[] a, char[] b) {
+ for (int i = 0; i < a.length; i++) {
+ if (a[i] != b[i]) {
+ failedCompare(i, "" + a[i], "" + b[i]);
+ }
+ }
}
- 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 compare(float[] a, float[] b) {
+ for (int i = 0; i < a.length; i++) {
+ if (a[i] != b[i]) {
+ failedCompare(i, "" + a[i], "" + b[i]);
+ }
+ }
+ }
+
+ private static void compare(double[] a, double[] b) {
+ for (int i = 0; i < a.length; i++) {
+ if (a[i] != b[i]) {
+ failedCompare(i, "" + a[i], "" + b[i]);
+ }
+ }
+ }
+
+ private static void compare(Integer[] a, Integer[] b) {
+ for (int i = 0; i < a.length; i++) {
+ if (a[i].compareTo(b[i]) != 0) {
+ failedCompare(i, "" + a[i], "" + b[i]);
+ }
+ }
}
private static void checkSorted(Object object) {
@@ -983,82 +1079,10 @@
}
}
- 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) {
- for (int i = 0; i < a.length; i++) {
- if (a[i] != b[i]) {
- failed(i, "" + a[i], "" + b[i]);
- }
- }
- }
-
- private static void compare(long[] a, long[] b) {
- for (int i = 0; i < a.length; i++) {
- if (a[i] != b[i]) {
- failed(i, "" + a[i], "" + b[i]);
- }
- }
- }
-
- private static void compare(short[] a, short[] b) {
- for (int i = 0; i < a.length; i++) {
- if (a[i] != b[i]) {
- failed(i, "" + a[i], "" + b[i]);
- }
- }
- }
-
- private static void compare(byte[] a, byte[] b) {
- for (int i = 0; i < a.length; i++) {
- if (a[i] != b[i]) {
- failed(i, "" + a[i], "" + b[i]);
- }
- }
- }
-
- private static void compare(char[] a, char[] b) {
- for (int i = 0; i < a.length; i++) {
- if (a[i] != b[i]) {
- failed(i, "" + a[i], "" + b[i]);
- }
- }
- }
-
- private static void compare(float[] a, float[] b) {
- for (int i = 0; i < a.length; i++) {
- if (a[i] != b[i]) {
- failed(i, "" + a[i], "" + b[i]);
- }
- }
- }
-
- private static void compare(double[] a, double[] b) {
- for (int i = 0; i < a.length; i++) {
- if (a[i] != b[i]) {
- failed(i, "" + a[i], "" + b[i]);
- }
- }
- }
-
- private static void checkSorted(Integer[] a) {
- for (int i = 0; i < a.length - 1; i++) {
- if (a[i].intValue() > a[i + 1].intValue()) {
- failed(i, "" + a[i], "" + a[i + 1]);
- }
- }
- }
-
private static void checkSorted(int[] a) {
for (int i = 0; i < a.length - 1; i++) {
if (a[i] > a[i + 1]) {
- failed(i, "" + a[i], "" + a[i + 1]);
+ failedSort(i, "" + a[i], "" + a[i + 1]);
}
}
}
@@ -1066,7 +1090,7 @@
private static void checkSorted(long[] a) {
for (int i = 0; i < a.length - 1; i++) {
if (a[i] > a[i + 1]) {
- failed(i, "" + a[i], "" + a[i + 1]);
+ failedSort(i, "" + a[i], "" + a[i + 1]);
}
}
}
@@ -1074,7 +1098,7 @@
private static void checkSorted(short[] a) {
for (int i = 0; i < a.length - 1; i++) {
if (a[i] > a[i + 1]) {
- failed(i, "" + a[i], "" + a[i + 1]);
+ failedSort(i, "" + a[i], "" + a[i + 1]);
}
}
}
@@ -1082,7 +1106,7 @@
private static void checkSorted(byte[] a) {
for (int i = 0; i < a.length - 1; i++) {
if (a[i] > a[i + 1]) {
- failed(i, "" + a[i], "" + a[i + 1]);
+ failedSort(i, "" + a[i], "" + a[i + 1]);
}
}
}
@@ -1090,7 +1114,7 @@
private static void checkSorted(char[] a) {
for (int i = 0; i < a.length - 1; i++) {
if (a[i] > a[i + 1]) {
- failed(i, "" + a[i], "" + a[i + 1]);
+ failedSort(i, "" + a[i], "" + a[i + 1]);
}
}
}
@@ -1098,7 +1122,7 @@
private static void checkSorted(float[] a) {
for (int i = 0; i < a.length - 1; i++) {
if (a[i] > a[i + 1]) {
- failed(i, "" + a[i], "" + a[i + 1]);
+ failedSort(i, "" + a[i], "" + a[i + 1]);
}
}
}
@@ -1106,34 +1130,141 @@
private static void checkSorted(double[] a) {
for (int i = 0; i < a.length - 1; i++) {
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) {
- if (checkSum(test) != checkSum(golden)) {
- failed("It seems that original and sorted arrays are not identical");
+ if (checkSumXor(test) != checkSumXor(golden)) {
+ 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 checkSumXor(Object object) {
+ if (object instanceof int[]) {
+ return checkSumXor((int[]) object);
+ } else if (object instanceof long[]) {
+ return checkSumXor((long[]) object);
+ } else if (object instanceof short[]) {
+ return checkSumXor((short[]) object);
+ } else if (object instanceof byte[]) {
+ return checkSumXor((byte[]) object);
+ } else if (object instanceof char[]) {
+ return checkSumXor((char[]) object);
+ } else if (object instanceof float[]) {
+ return checkSumXor((float[]) object);
+ } else if (object instanceof double[]) {
+ return checkSumXor((double[]) object);
+ } else if (object instanceof Integer[]) {
+ return checkSumXor((Integer[]) object);
+ } else {
+ failed("Unknow type of array: " + object + " of class " +
+ object.getClass().getName());
+ return -1;
}
}
- private static int checkSum(Object object) {
+ private static int checkSumXor(Integer[] a) {
+ int checkSum = 0;
+
+ for (Integer e : a) {
+ checkSum ^= e.intValue();
+ }
+ return checkSum;
+ }
+
+ private static int checkSumXor(int[] a) {
+ int checkSum = 0;
+
+ for (int e : a) {
+ checkSum ^= e;
+ }
+ return checkSum;
+ }
+
+ private static int checkSumXor(long[] a) {
+ long checkSum = 0;
+
+ for (long e : a) {
+ checkSum ^= e;
+ }
+ return (int) checkSum;
+ }
+
+ private static int checkSumXor(short[] a) {
+ short checkSum = 0;
+
+ for (short e : a) {
+ checkSum ^= e;
+ }
+ return (int) checkSum;
+ }
+
+ private static int checkSumXor(byte[] a) {
+ byte checkSum = 0;
+
+ for (byte e : a) {
+ checkSum ^= e;
+ }
+ return (int) checkSum;
+ }
+
+ private static int checkSumXor(char[] a) {
+ char checkSum = 0;
+
+ for (char e : a) {
+ checkSum ^= e;
+ }
+ return (int) checkSum;
+ }
+
+ private static int checkSumXor(float[] a) {
+ int checkSum = 0;
+
+ for (float e : a) {
+ checkSum ^= (int) e;
+ }
+ return checkSum;
+ }
+
+ private static int checkSumXor(double[] a) {
+ int checkSum = 0;
+
+ for (double e : a) {
+ checkSum ^= (int) e;
+ }
+ return checkSum;
+ }
+
+ private static int checkSumPlus(Object object) {
if (object instanceof int[]) {
- return checkSum((int[]) object);
+ return checkSumPlus((int[]) object);
} else if (object instanceof long[]) {
- return checkSum((long[]) object);
+ return checkSumPlus((long[]) object);
} else if (object instanceof short[]) {
- return checkSum((short[]) object);
+ return checkSumPlus((short[]) object);
} else if (object instanceof byte[]) {
- return checkSum((byte[]) object);
+ return checkSumPlus((byte[]) object);
} else if (object instanceof char[]) {
- return checkSum((char[]) object);
+ return checkSumPlus((char[]) object);
} else if (object instanceof float[]) {
- return checkSum((float[]) object);
+ return checkSumPlus((float[]) object);
} else if (object instanceof double[]) {
- return checkSum((double[]) object);
+ return checkSumPlus((double[]) object);
} else if (object instanceof Integer[]) {
- return checkSum((Integer[]) object);
+ return checkSumPlus((Integer[]) object);
} else {
failed("Unknow type of array: " + object + " of class " +
object.getClass().getName());
@@ -1141,76 +1272,179 @@
}
}
- private static int checkSum(Integer[] a) {
- int checkXorSum = 0;
-
- for (Integer e : a) {
- checkXorSum ^= e.intValue();
- }
- return checkXorSum;
- }
-
- private static int checkSum(int[] a) {
- int checkXorSum = 0;
+ private static int checkSumPlus(int[] a) {
+ int checkSum = 0;
for (int e : a) {
- checkXorSum ^= e;
+ checkSum += e;
}
- return checkXorSum;
+ return checkSum;
}
- private static int checkSum(long[] a) {
- long checkXorSum = 0;
+ private static int checkSumPlus(long[] a) {
+ long checkSum = 0;
for (long e : a) {
- checkXorSum ^= e;
+ checkSum += e;
}
- return (int) checkXorSum;
+ return (int) checkSum;
}
- private static int checkSum(short[] a) {
- short checkXorSum = 0;
+ private static int checkSumPlus(short[] a) {
+ short checkSum = 0;
for (short e : a) {
- checkXorSum ^= e;
+ checkSum += e;
}
- return (int) checkXorSum;
+ return (int) checkSum;
}
- private static int checkSum(byte[] a) {
- byte checkXorSum = 0;
+ private static int checkSumPlus(byte[] a) {
+ byte checkSum = 0;
for (byte e : a) {
- checkXorSum ^= e;
+ checkSum += e;
}
- return (int) checkXorSum;
+ return (int) checkSum;
}
- private static int checkSum(char[] a) {
- char checkXorSum = 0;
+ private static int checkSumPlus(char[] a) {
+ char checkSum = 0;
for (char e : a) {
- checkXorSum ^= e;
+ checkSum += e;
}
- return (int) checkXorSum;
+ return (int) checkSum;
}
- private static int checkSum(float[] a) {
- int checkXorSum = 0;
+ private static int checkSumPlus(float[] a) {
+ int checkSum = 0;
for (float e : a) {
- checkXorSum ^= (int) e;
+ 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 checkXorSum;
+ 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 int checkSum(double[] a) {
- int checkXorSum = 0;
+ 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;
+ }
+ }
- for (double e : a) {
- checkXorSum ^= (int) e;
+ 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;
}
- return checkXorSum;
+ }
+
+ 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;
+ }
}
private static void sort(Object object) {
@@ -1292,7 +1526,7 @@
for (int i = fromIndex; i < toIndex - 1; i++) {
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 @@
for (int i = fromIndex; i < toIndex - 1; i++) {
if (a[i] > a[i + 1]) {
- failed(i, "" + a[i], "" + a[i + 1]);
+ failedSort(i, "" + a[i], "" + a[i + 1]);
}
}
@@ -1336,7 +1570,7 @@
for (int i = fromIndex; i < toIndex - 1; i++) {
if (a[i] > a[i + 1]) {
- failed(i, "" + a[i], "" + a[i + 1]);
+ failedSort(i, "" + a[i], "" + a[i + 1]);
}
}
@@ -1358,7 +1592,7 @@
for (int i = fromIndex; i < toIndex - 1; i++) {
if (a[i] > a[i + 1]) {
- failed(i, "" + a[i], "" + a[i + 1]);
+ failedSort(i, "" + a[i], "" + a[i + 1]);
}
}
@@ -1380,7 +1614,7 @@
for (int i = fromIndex; i < toIndex - 1; i++) {
if (a[i] > a[i + 1]) {
- failed(i, "" + a[i], "" + a[i + 1]);
+ failedSort(i, "" + a[i], "" + a[i + 1]);
}
}
@@ -1402,7 +1636,7 @@
for (int i = fromIndex; i < toIndex - 1; i++) {
if (a[i] > a[i + 1]) {
- failed(i, "" + a[i], "" + a[i + 1]);
+ failedSort(i, "" + a[i], "" + a[i + 1]);
}
}
@@ -1424,7 +1658,7 @@
for (int i = fromIndex; i < toIndex - 1; i++) {
if (a[i] > a[i + 1]) {
- failed(i, "" + a[i], "" + a[i + 1]);
+ failedSort(i, "" + a[i], "" + a[i + 1]);
}
}
@@ -1446,7 +1680,7 @@
for (int i = fromIndex; i < toIndex - 1; i++) {
if (a[i] > a[i + 1]) {
- failed(i, "" + a[i], "" + a[i + 1]);
+ failedSort(i, "" + a[i], "" + a[i + 1]);
}
}