From 090a9645093b631180b75055fb4c7d703236e141 Mon Sep 17 00:00:00 2001 From: alanb Date: Fri, 15 Oct 2010 12:10:32 +0100 Subject: [PATCH] 6976036: Dual-pivot quicksort update (10/2010 tune-up) Reviewed-by: alanb Contributed-by: vladimir.yaroslavskiy@oracle.com --- src/share/classes/java/util/Arrays.java | 22 +- .../classes/java/util/DualPivotQuicksort.java | 1464 +++++++---------- test/java/util/Arrays/Sorting.java | 498 ++++-- 3 files changed, 963 insertions(+), 1021 deletions(-) diff --git a/src/share/classes/java/util/Arrays.java b/src/share/classes/java/util/Arrays.java index 54abbb27c..b4951e14f 100644 --- a/src/share/classes/java/util/Arrays.java +++ b/src/share/classes/java/util/Arrays.java @@ -97,7 +97,8 @@ public class Arrays { * if {@code fromIndex < 0} or {@code toIndex > a.length} */ 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 { * if {@code fromIndex < 0} or {@code toIndex > a.length} */ 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 { * if {@code fromIndex < 0} or {@code toIndex > a.length} */ 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 { * if {@code fromIndex < 0} or {@code toIndex > a.length} */ 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 { * if {@code fromIndex < 0} or {@code toIndex > a.length} */ 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 { * if {@code fromIndex < 0} or {@code toIndex > a.length} */ 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 { * if {@code fromIndex < 0} or {@code toIndex > a.length} */ 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. - * */ /** diff --git a/src/share/classes/java/util/DualPivotQuicksort.java b/src/share/classes/java/util/DualPivotQuicksort.java index 873230a2c..616ee2e2f 100644 --- a/src/share/classes/java/util/DualPivotQuicksort.java +++ b/src/share/classes/java/util/DualPivotQuicksort.java @@ -36,7 +36,7 @@ package java.util; * @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 @@ final class DualPivotQuicksort { * 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 @@ final class DualPivotQuicksort { } /** - * 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(int[] a, int fromIndex, int toIndex) { - rangeCheck(a.length, fromIndex, toIndex); - sort(a, fromIndex, toIndex - 1, true); + public static void sort(int[] a, int left, int right) { + sort(a, left, right, 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 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(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 @@ final class DualPivotQuicksort { } 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 @@ final class DualPivotQuicksort { * 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 @@ final class DualPivotQuicksort { 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 @@ final class DualPivotQuicksort { 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 @@ final class DualPivotQuicksort { * 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 @@ final class DualPivotQuicksort { 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 @@ final class DualPivotQuicksort { } 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 @@ final class DualPivotQuicksort { * * 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 @@ 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, 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 @@ final class DualPivotQuicksort { } /** - * 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(long[] a, int fromIndex, int toIndex) { - rangeCheck(a.length, fromIndex, toIndex); - sort(a, fromIndex, toIndex - 1, true); + public static void sort(long[] a, int left, int right) { + sort(a, left, right, 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 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(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) { - /* - * 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 { + if (leftmost) { /* - * 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,381 +474,54 @@ final class DualPivotQuicksort { } 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]) { 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) { + } else { /* - * Skip elements, which are equal to pivot values. + * Skip the longest ascending sequence. */ - while (a[less] == pivot1) { - less++; - } - while (a[great] == pivot2) { - great--; - } + do { + if (left++ >= right) { + return; + } + } while (a[left - 1] <= a[left]); /* - * 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. + * 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. */ - 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]; - /* - * 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--; - } - } - } + for (int k = left--; (left += 2) <= right; ) { + long a1, a2; k = left - 1; - // 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; - } - 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[k] < a[left]) { + a2 = a[k]; a1 = a[left]; + } else { + a1 = a[k]; a2 = a[left]; } - 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; + while (a1 < a[--k]) { + a[k + 2] = a[k]; } - a[great] = ak; - great--; - } - } - - // Sort left and right parts recursively - sort(a, left, less - 1, leftmost); - sort(a, great + 1, right, false); - } - } + a[++k + 1] = a1; - /** - * Sorts the specified array into ascending numerical order. - * - * @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]; + while (a2 < a[--k]) { + a[k + 1] = a[k]; } - a[j + 1] = ai; + a[k + 1] = a2; } - } 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) { - short ai = a[i + 1]; - while (ai < a[j]) { - a[j + 1] = a[j]; - if (j-- == left) { - break; - } - } - a[j + 1] = ai; + 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 @@ -866,17 +537,17 @@ final class DualPivotQuicksort { int e5 = e4 + seventh; // 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 (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[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[e2]) { a[e3] = a[e2]; a[e2] = t; if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } @@ -889,8 +560,8 @@ final class DualPivotQuicksort { * These values are inexpensive approximations of the first and * second terciles of the array. Note that pivot1 <= pivot2. */ - short pivot1 = a[e2]; - short pivot2 = a[e4]; + long pivot1 = a[e2]; + long pivot2 = a[e4]; // Pointers int less = left; // The index of the first element of center part @@ -932,10 +603,14 @@ final class DualPivotQuicksort { * Pointer k is the first index of ?-part. */ outer: - for (int k = less; k <= great; k++) { - short ak = a[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 @@ -944,13 +619,17 @@ final class DualPivotQuicksort { 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 +644,7 @@ final class DualPivotQuicksort { 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,8 +678,8 @@ final class DualPivotQuicksort { * Pointer k is the first index of ?-part. */ outer: - for (int k = less; k <= great; k++) { - short ak = a[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]; a[less] = ak; @@ -1011,7 +690,7 @@ final class DualPivotQuicksort { 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 +716,7 @@ final class DualPivotQuicksort { } 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 +735,20 @@ final class DualPivotQuicksort { * * 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]; - + 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++; @@ -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, great + 1, right, false); } } /** - * Sorts the specified array into ascending numerical order. - * - * @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). + * Sorts the specified 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} */ - public static void sort(char[] 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); - } + public static void sort(short[] a) { + sort(a, 0, a.length - 1); } - /** 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 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]; + 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]; - for (int i = left; i <= right; i++) { - count[a[i]]++; - } - for (int i = 0, k = left; k <= right; i++) { - while (count[i] == 0) { - i++; + for (int i = left - 1; ++i <= right; ) { + count[a[i] - Short.MIN_VALUE]++; } - char value = (char) i; - int s = count[i]; - - do { - a[k++] = value; - } while (--s > 0); + 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); } } + /** 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 - * 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(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; - // Use insertion sort on tiny arrays + // Use insertion sort on small 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++) { - 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 { + if (leftmost) { /* - * 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]; + short ai = a[i + 1]; while (ai < a[j]) { a[j + 1] = a[j]; if (j-- == left) { @@ -1214,12 +848,54 @@ final class DualPivotQuicksort { } 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 @@ -1235,17 +911,17 @@ final class DualPivotQuicksort { int e5 = e4 + seventh; // 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 (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[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[e2]) { a[e3] = a[e2]; a[e2] = t; if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } @@ -1258,8 +934,8 @@ final class DualPivotQuicksort { * These values are inexpensive approximations of the first and * second terciles of the array. Note that pivot1 <= pivot2. */ - char pivot1 = a[e2]; - char pivot2 = a[e4]; + short pivot1 = a[e2]; + short pivot2 = a[e4]; // Pointers int less = left; // The index of the first element of center part @@ -1301,10 +977,14 @@ final class DualPivotQuicksort { * Pointer k is the first index of ?-part. */ outer: - for (int k = less; k <= great; k++) { - char ak = a[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 @@ -1313,13 +993,17 @@ final class DualPivotQuicksort { 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 +1018,7 @@ final class DualPivotQuicksort { 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,8 +1052,8 @@ final class DualPivotQuicksort { * Pointer k is the first index of ?-part. */ outer: - for (int k = less; k <= great; k++) { - char ak = a[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]; a[less] = ak; @@ -1380,7 +1064,7 @@ final class DualPivotQuicksort { 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 +1090,7 @@ final class DualPivotQuicksort { } 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 +1109,20 @@ final class DualPivotQuicksort { * * 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]; - + 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++; @@ -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, 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(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); - } + public static void sort(char[] a) { + sort(a, 0, a.length - 1); } - /** 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 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(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]; - 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--; + for (int i = left - 1; ++i <= right; ) { + count[a[i]]++; } - byte value = (byte) (i + Byte.MIN_VALUE); - int s = count[i]; - - do { - a[k--] = value; - } while (--s > 0); + 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); } } + /** 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 - * 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(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; - // Use insertion sort on tiny arrays + // Use insertion sort on small 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 { + if (leftmost) { /* - * 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) { - byte ai = a[i + 1]; + char ai = a[i + 1]; while (ai < a[j]) { a[j + 1] = a[j]; if (j-- == left) { @@ -1583,12 +1222,54 @@ final class DualPivotQuicksort { } 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 @@ -1604,17 +1285,17 @@ final class DualPivotQuicksort { 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[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 (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[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[e2]) { a[e3] = a[e2]; a[e2] = t; if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } @@ -1627,8 +1308,8 @@ final class DualPivotQuicksort { * 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]; + char pivot1 = a[e2]; + char pivot2 = a[e4]; // Pointers int less = left; // The index of the first element of center part @@ -1670,10 +1351,14 @@ final class DualPivotQuicksort { * Pointer k is the first index of ?-part. */ outer: - for (int k = less; k <= great; k++) { - byte ak = a[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 @@ -1682,13 +1367,17 @@ final class DualPivotQuicksort { 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--; } @@ -1703,7 +1392,7 @@ final class DualPivotQuicksort { 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) { @@ -1737,8 +1426,8 @@ final class DualPivotQuicksort { * Pointer k is the first index of ?-part. */ outer: - for (int k = less; k <= great; k++) { - byte ak = a[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]; a[less] = ak; @@ -1749,7 +1438,7 @@ final class DualPivotQuicksort { 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 @@ -1775,7 +1464,7 @@ final class DualPivotQuicksort { } 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 @@ -1794,28 +1483,20 @@ final class DualPivotQuicksort { * * 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; } - byte ak = a[k]; - + 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++; @@ -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, 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. - * - *

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); + public static void sort(byte[] a) { + 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. * - *

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 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(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]; + + 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 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); + public static void sort(float[] a) { + sort(a, 0, a.length - 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 @@ final class DualPivotQuicksort { 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 @@ final class DualPivotQuicksort { * * 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 @@ final class DualPivotQuicksort { * * 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) { - /* - * 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 { + if (leftmost) { /* - * 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 @@ final class DualPivotQuicksort { } 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 @@ final class DualPivotQuicksort { * 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 @@ final class DualPivotQuicksort { 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 @@ final class DualPivotQuicksort { 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 @@ final class DualPivotQuicksort { * 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 @@ final class DualPivotQuicksort { 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 @@ final class DualPivotQuicksort { } 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 @@ final class DualPivotQuicksort { * * 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 @@ 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, great + 1, right, false); } } /** - * Sorts the specified array into ascending numerical order. - * - *

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); - } - - /** - * 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). - * - *

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); + sort(a, 0, a.length - 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 @@ final class DualPivotQuicksort { 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 @@ final class DualPivotQuicksort { * * 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 @@ final class DualPivotQuicksort { * * 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) { - /* - * 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 { + if (leftmost) { /* - * 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 @@ final class DualPivotQuicksort { } 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 @@ final class DualPivotQuicksort { * 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 @@ final class DualPivotQuicksort { 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 @@ final class DualPivotQuicksort { 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 @@ final class DualPivotQuicksort { * 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 @@ final class DualPivotQuicksort { 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 @@ final class DualPivotQuicksort { } 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 @@ final class DualPivotQuicksort { * * 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 @@ 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, 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); - } - } } diff --git a/test/java/util/Arrays/Sorting.java b/test/java/util/Arrays/Sorting.java index cee7f5330..a2c4ed98e 100644 --- a/test/java/util/Arrays/Sorting.java +++ b/test/java/util/Arrays/Sorting.java @@ -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 @@ public class Sorting { 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"); @@ -81,6 +81,11 @@ public class Sorting { for (long random : randoms) { reset(random); + for (int length : lengths) { + testAndCheckWithInsertionSort(length, random); + } + reset(random); + for (int length : lengths) { testAndCheckWithCheckSum(length, random); } @@ -268,9 +273,7 @@ public class Sorting { " 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 @@ public class Sorting { 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 @@ public class Sorting { 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 @@ public class Sorting { 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 @@ public class Sorting { 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 @@ public class Sorting { 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 @@ public class Sorting { 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 @@ public class Sorting { 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 @@ public class Sorting { 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 @@ 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) { if (test instanceof int[]) { compare((int[]) test, (int[]) golden); @@ -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) { for (int i = 0; i < a.length; 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 { 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]); + failedCompare(i, "" + a[i], "" + b[i]); } } } @@ -1010,7 +1011,7 @@ public class Sorting { 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]); + failedCompare(i, "" + a[i], "" + b[i]); } } } @@ -1018,7 +1019,7 @@ public class Sorting { 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]); + failedCompare(i, "" + a[i], "" + b[i]); } } } @@ -1026,7 +1027,7 @@ public class Sorting { 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]); + failedCompare(i, "" + a[i], "" + b[i]); } } } @@ -1034,7 +1035,7 @@ public class Sorting { 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]); + failedCompare(i, "" + a[i], "" + b[i]); } } } @@ -1042,23 +1043,46 @@ public class Sorting { 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]); + failedCompare(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 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) { + 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) { 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 @@ public class Sorting { 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 @@ public class Sorting { 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 @@ public class Sorting { 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 @@ public class Sorting { 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 @@ public class Sorting { 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,45 @@ public class Sorting { 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 checkSum(Object object) { + private static int checkSumXor(Object object) { if (object instanceof int[]) { - return checkSum((int[]) object); + return checkSumXor((int[]) object); } else if (object instanceof long[]) { - return checkSum((long[]) object); + return checkSumXor((long[]) object); } else if (object instanceof short[]) { - return checkSum((short[]) object); + return checkSumXor((short[]) object); } else if (object instanceof byte[]) { - return checkSum((byte[]) object); + return checkSumXor((byte[]) object); } else if (object instanceof char[]) { - return checkSum((char[]) object); + return checkSumXor((char[]) object); } else if (object instanceof float[]) { - return checkSum((float[]) object); + return checkSumXor((float[]) object); } else if (object instanceof double[]) { - return checkSum((double[]) object); + return checkSumXor((double[]) object); } else if (object instanceof Integer[]) { - return checkSum((Integer[]) object); + return checkSumXor((Integer[]) object); } else { failed("Unknow type of array: " + object + " of class " + object.getClass().getName()); @@ -1141,76 +1176,275 @@ public class Sorting { } } - private static int checkSum(Integer[] a) { - int checkXorSum = 0; + private static int checkSumXor(Integer[] a) { + int checkSum = 0; for (Integer e : a) { - checkXorSum ^= e.intValue(); + checkSum ^= e.intValue(); } - return checkXorSum; + return checkSum; } - private static int checkSum(int[] a) { - int checkXorSum = 0; + private static int checkSumXor(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 checkSumXor(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 checkSumXor(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 checkSumXor(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 checkSumXor(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 checkSumXor(float[] a) { + int checkSum = 0; for (float e : a) { - checkXorSum ^= (int) e; + checkSum ^= (int) e; } - return checkXorSum; + return checkSum; } - private static int checkSum(double[] a) { - int checkXorSum = 0; + private static int checkSumXor(double[] a) { + int checkSum = 0; 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) { @@ -1292,7 +1526,7 @@ public class Sorting { 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 @@ public class Sorting { 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 @@ public class Sorting { 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 @@ public class Sorting { 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 @@ public class Sorting { 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 @@ public class Sorting { 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 @@ public class Sorting { 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 @@ public class Sorting { 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]); } } -- GitLab