)first).compareTo(second);
- }
- static final NaturalOrder INSTANCE = new NaturalOrder();
- }
-
- /**
* Checks that {@code fromIndex} and {@code toIndex} are in
* the range and throws an exception if they aren't.
*/
@@ -124,9 +93,15 @@
}
}
+ /**
+ * This flag allows system to run sorting in parallel.
+ */
+ private static final boolean RUN_IN_PARALLEL =
+ Runtime.getRuntime().availableProcessors() > 1;
+
/*
* Sorting methods. Note that all public "sort" methods take the
- * same form: Performing argument checks if necessary, and then
+ * same form: performing argument checks if necessary, and then
* expanding arguments into those required for the internal
* implementation methods residing in other package-private
* classes (except for legacyMergeSort, included in this class).
@@ -135,16 +110,15 @@
/**
* Sorts the specified array into ascending numerical order.
*
- * Implementation note: The sorting algorithm is a Dual-Pivot Quicksort
- * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
- * offers O(n log(n)) performance on many data sets that cause other
- * quicksorts to degrade to quadratic performance, and is typically
+ * @implNote The sorting algorithm is a Dual-Pivot Quicksort by
+ * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm
+ * offers O(n log(n)) performance on all data sets, and is typically
* faster than traditional (one-pivot) Quicksort implementations.
*
* @param a the array to be sorted
*/
public static void sort(int[] a) {
- DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
+ DualPivotQuicksort.sort(a, false, 0, a.length);
}
/**
@@ -153,10 +127,9 @@
* the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
* the range to be sorted is empty.
*
- *
Implementation note: The sorting algorithm is a Dual-Pivot Quicksort
- * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
- * offers O(n log(n)) performance on many data sets that cause other
- * quicksorts to degrade to quadratic performance, and is typically
+ * @implNote The sorting algorithm is a Dual-Pivot Quicksort by
+ * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm
+ * offers O(n log(n)) performance on all data sets, and is typically
* faster than traditional (one-pivot) Quicksort implementations.
*
* @param a the array to be sorted
@@ -169,22 +142,21 @@
*/
public static void sort(int[] a, int fromIndex, int toIndex) {
rangeCheck(a.length, fromIndex, toIndex);
- DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
+ DualPivotQuicksort.sort(a, false, fromIndex, toIndex);
}
/**
* Sorts the specified array into ascending numerical order.
*
- *
Implementation note: The sorting algorithm is a Dual-Pivot Quicksort
- * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
- * offers O(n log(n)) performance on many data sets that cause other
- * quicksorts to degrade to quadratic performance, and is typically
+ * @implNote The sorting algorithm is a Dual-Pivot Quicksort by
+ * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm
+ * offers O(n log(n)) performance on all data sets, and is typically
* faster than traditional (one-pivot) Quicksort implementations.
*
* @param a the array to be sorted
*/
public static void sort(long[] a) {
- DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
+ DualPivotQuicksort.sort(a, false, 0, a.length);
}
/**
@@ -193,10 +165,9 @@
* the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
* the range to be sorted is empty.
*
- *
Implementation note: The sorting algorithm is a Dual-Pivot Quicksort
- * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
- * offers O(n log(n)) performance on many data sets that cause other
- * quicksorts to degrade to quadratic performance, and is typically
+ * @implNote The sorting algorithm is a Dual-Pivot Quicksort by
+ * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm
+ * offers O(n log(n)) performance on all data sets, and is typically
* faster than traditional (one-pivot) Quicksort implementations.
*
* @param a the array to be sorted
@@ -209,22 +180,21 @@
*/
public static void sort(long[] a, int fromIndex, int toIndex) {
rangeCheck(a.length, fromIndex, toIndex);
- DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
+ DualPivotQuicksort.sort(a, false, fromIndex, toIndex);
}
/**
* Sorts the specified array into ascending numerical order.
*
- *
Implementation note: The sorting algorithm is a Dual-Pivot Quicksort
- * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
- * offers O(n log(n)) performance on many data sets that cause other
- * quicksorts to degrade to quadratic performance, and is typically
+ * @implNote The sorting algorithm is a Dual-Pivot Quicksort by
+ * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm
+ * offers O(n log(n)) performance on all data sets, and is typically
* faster than traditional (one-pivot) Quicksort implementations.
*
* @param a the array to be sorted
*/
- public static void sort(short[] a) {
- DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
+ public static void sort(byte[] a) {
+ DualPivotQuicksort.sort(a, false, 0, a.length);
}
/**
@@ -233,10 +203,9 @@
* the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
* the range to be sorted is empty.
*
- *
Implementation note: The sorting algorithm is a Dual-Pivot Quicksort
- * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
- * offers O(n log(n)) performance on many data sets that cause other
- * quicksorts to degrade to quadratic performance, and is typically
+ * @implNote The sorting algorithm is a Dual-Pivot Quicksort by
+ * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm
+ * offers O(n log(n)) performance on all data sets, and is typically
* faster than traditional (one-pivot) Quicksort implementations.
*
* @param a the array to be sorted
@@ -247,24 +216,23 @@
* @throws ArrayIndexOutOfBoundsException
* if {@code fromIndex < 0} or {@code toIndex > a.length}
*/
- public static void sort(short[] a, int fromIndex, int toIndex) {
+ public static void sort(byte[] a, int fromIndex, int toIndex) {
rangeCheck(a.length, fromIndex, toIndex);
- DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
+ DualPivotQuicksort.sort(a, false, fromIndex, toIndex);
}
/**
* Sorts the specified array into ascending numerical order.
*
- *
Implementation note: The sorting algorithm is a Dual-Pivot Quicksort
- * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
- * offers O(n log(n)) performance on many data sets that cause other
- * quicksorts to degrade to quadratic performance, and is typically
+ * @implNote The sorting algorithm is a Dual-Pivot Quicksort by
+ * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm
+ * offers O(n log(n)) performance on all data sets, and is typically
* faster than traditional (one-pivot) Quicksort implementations.
*
* @param a the array to be sorted
*/
public static void sort(char[] a) {
- DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
+ DualPivotQuicksort.sort(a, false, 0, a.length);
}
/**
@@ -273,10 +241,9 @@
* the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
* the range to be sorted is empty.
*
- *
Implementation note: The sorting algorithm is a Dual-Pivot Quicksort
- * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
- * offers O(n log(n)) performance on many data sets that cause other
- * quicksorts to degrade to quadratic performance, and is typically
+ * @implNote The sorting algorithm is a Dual-Pivot Quicksort by
+ * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm
+ * offers O(n log(n)) performance on all data sets, and is typically
* faster than traditional (one-pivot) Quicksort implementations.
*
* @param a the array to be sorted
@@ -289,22 +256,21 @@
*/
public static void sort(char[] a, int fromIndex, int toIndex) {
rangeCheck(a.length, fromIndex, toIndex);
- DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
+ DualPivotQuicksort.sort(a, false, fromIndex, toIndex);
}
/**
* Sorts the specified array into ascending numerical order.
*
- *
Implementation note: The sorting algorithm is a Dual-Pivot Quicksort
- * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
- * offers O(n log(n)) performance on many data sets that cause other
- * quicksorts to degrade to quadratic performance, and is typically
+ * @implNote The sorting algorithm is a Dual-Pivot Quicksort by
+ * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm
+ * offers O(n log(n)) performance on all data sets, and is typically
* faster than traditional (one-pivot) Quicksort implementations.
*
* @param a the array to be sorted
*/
- public static void sort(byte[] a) {
- DualPivotQuicksort.sort(a, 0, a.length - 1);
+ public static void sort(short[] a) {
+ DualPivotQuicksort.sort(a, false, 0, a.length);
}
/**
@@ -313,10 +279,9 @@
* the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
* the range to be sorted is empty.
*
- *
Implementation note: The sorting algorithm is a Dual-Pivot Quicksort
- * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
- * offers O(n log(n)) performance on many data sets that cause other
- * quicksorts to degrade to quadratic performance, and is typically
+ * @implNote The sorting algorithm is a Dual-Pivot Quicksort by
+ * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm
+ * offers O(n log(n)) performance on all data sets, and is typically
* faster than traditional (one-pivot) Quicksort implementations.
*
* @param a the array to be sorted
@@ -327,9 +292,9 @@
* @throws ArrayIndexOutOfBoundsException
* if {@code fromIndex < 0} or {@code toIndex > a.length}
*/
- public static void sort(byte[] a, int fromIndex, int toIndex) {
+ public static void sort(short[] a, int fromIndex, int toIndex) {
rangeCheck(a.length, fromIndex, toIndex);
- DualPivotQuicksort.sort(a, fromIndex, toIndex - 1);
+ DualPivotQuicksort.sort(a, false, fromIndex, toIndex);
}
/**
@@ -343,16 +308,15 @@
* {@code 0.0f} and {@code Float.NaN} is considered greater than any
* other value and all {@code Float.NaN} values are considered equal.
*
- *
Implementation note: The sorting algorithm is a Dual-Pivot Quicksort
- * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
- * offers O(n log(n)) performance on many data sets that cause other
- * quicksorts to degrade to quadratic performance, and is typically
+ * @implNote The sorting algorithm is a Dual-Pivot Quicksort by
+ * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm
+ * offers O(n log(n)) performance on all data sets, and is typically
* faster than traditional (one-pivot) Quicksort implementations.
*
* @param a the array to be sorted
*/
public static void sort(float[] a) {
- DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
+ DualPivotQuicksort.sort(a, false, 0, a.length);
}
/**
@@ -369,10 +333,9 @@
* {@code 0.0f} and {@code Float.NaN} is considered greater than any
* other value and all {@code Float.NaN} values are considered equal.
*
- *
Implementation note: The sorting algorithm is a Dual-Pivot Quicksort
- * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
- * offers O(n log(n)) performance on many data sets that cause other
- * quicksorts to degrade to quadratic performance, and is typically
+ * @implNote The sorting algorithm is a Dual-Pivot Quicksort by
+ * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm
+ * offers O(n log(n)) performance on all data sets, and is typically
* faster than traditional (one-pivot) Quicksort implementations.
*
* @param a the array to be sorted
@@ -385,7 +348,7 @@
*/
public static void sort(float[] a, int fromIndex, int toIndex) {
rangeCheck(a.length, fromIndex, toIndex);
- DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
+ DualPivotQuicksort.sort(a, false, fromIndex, toIndex);
}
/**
@@ -399,16 +362,15 @@
* {@code 0.0d} and {@code Double.NaN} is considered greater than any
* other value and all {@code Double.NaN} values are considered equal.
*
- *
Implementation note: The sorting algorithm is a Dual-Pivot Quicksort
- * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
- * offers O(n log(n)) performance on many data sets that cause other
- * quicksorts to degrade to quadratic performance, and is typically
+ * @implNote The sorting algorithm is a Dual-Pivot Quicksort by
+ * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm
+ * offers O(n log(n)) performance on all data sets, and is typically
* faster than traditional (one-pivot) Quicksort implementations.
*
* @param a the array to be sorted
*/
public static void sort(double[] a) {
- DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
+ DualPivotQuicksort.sort(a, false, 0, a.length);
}
/**
@@ -425,10 +387,9 @@
* {@code 0.0d} and {@code Double.NaN} is considered greater than any
* other value and all {@code Double.NaN} values are considered equal.
*
- *
Implementation note: The sorting algorithm is a Dual-Pivot Quicksort
- * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
- * offers O(n log(n)) performance on many data sets that cause other
- * quicksorts to degrade to quadratic performance, and is typically
+ * @implNote The sorting algorithm is a Dual-Pivot Quicksort by
+ * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm
+ * offers O(n log(n)) performance on all data sets, and is typically
* faster than traditional (one-pivot) Quicksort implementations.
*
* @param a the array to be sorted
@@ -441,37 +402,23 @@
*/
public static void sort(double[] a, int fromIndex, int toIndex) {
rangeCheck(a.length, fromIndex, toIndex);
- DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
+ DualPivotQuicksort.sort(a, false, fromIndex, toIndex);
}
/**
* Sorts the specified array into ascending numerical order.
*
- * @implNote The sorting algorithm is a parallel sort-merge that breaks the
- * array into sub-arrays that are themselves sorted and then merged. When
- * the sub-array length reaches a minimum granularity, the sub-array is
- * sorted using the appropriate {@link Arrays#sort(byte[]) Arrays.sort}
- * method. If the length of the specified array is less than the minimum
- * granularity, then it is sorted using the appropriate {@link
- * Arrays#sort(byte[]) Arrays.sort} method. The algorithm requires a
- * working space no greater than the size of the original array. The
- * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to
- * execute any parallel tasks.
+ * @implNote The sorting algorithm is a Dual-Pivot Quicksort by
+ * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm
+ * offers O(n log(n)) performance on all data sets, and is typically
+ * faster than traditional (one-pivot) Quicksort implementations.
*
* @param a the array to be sorted
*
* @since 1.8
*/
- public static void parallelSort(byte[] a) {
- int n = a.length, p, g;
- if (n <= MIN_ARRAY_SORT_GRAN ||
- (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
- DualPivotQuicksort.sort(a, 0, n - 1);
- else
- new ArraysParallelSortHelpers.FJByte.Sorter
- (null, a, new byte[n], 0, n, 0,
- ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
- MIN_ARRAY_SORT_GRAN : g).invoke();
+ public static void parallelSort(int[] a) {
+ DualPivotQuicksort.sort(a, RUN_IN_PARALLEL, 0, a.length);
}
/**
@@ -480,16 +427,10 @@
* inclusive, to the index {@code toIndex}, exclusive. If
* {@code fromIndex == toIndex}, the range to be sorted is empty.
*
- * @implNote The sorting algorithm is a parallel sort-merge that breaks the
- * array into sub-arrays that are themselves sorted and then merged. When
- * the sub-array length reaches a minimum granularity, the sub-array is
- * sorted using the appropriate {@link Arrays#sort(byte[]) Arrays.sort}
- * method. If the length of the specified array is less than the minimum
- * granularity, then it is sorted using the appropriate {@link
- * Arrays#sort(byte[]) Arrays.sort} method. The algorithm requires a working
- * space no greater than the size of the specified range of the original
- * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is
- * used to execute any parallel tasks.
+ * @implNote The sorting algorithm is a Dual-Pivot Quicksort by
+ * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm
+ * offers O(n log(n)) performance on all data sets, and is typically
+ * faster than traditional (one-pivot) Quicksort implementations.
*
* @param a the array to be sorted
* @param fromIndex the index of the first element, inclusive, to be sorted
@@ -501,47 +442,25 @@
*
* @since 1.8
*/
- public static void parallelSort(byte[] a, int fromIndex, int toIndex) {
+ public static void parallelSort(int[] a, int fromIndex, int toIndex) {
rangeCheck(a.length, fromIndex, toIndex);
- int n = toIndex - fromIndex, p, g;
- if (n <= MIN_ARRAY_SORT_GRAN ||
- (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
- DualPivotQuicksort.sort(a, fromIndex, toIndex - 1);
- else
- new ArraysParallelSortHelpers.FJByte.Sorter
- (null, a, new byte[n], fromIndex, n, 0,
- ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
- MIN_ARRAY_SORT_GRAN : g).invoke();
+ DualPivotQuicksort.sort(a, RUN_IN_PARALLEL, fromIndex, toIndex);
}
/**
* Sorts the specified array into ascending numerical order.
*
- * @implNote The sorting algorithm is a parallel sort-merge that breaks the
- * array into sub-arrays that are themselves sorted and then merged. When
- * the sub-array length reaches a minimum granularity, the sub-array is
- * sorted using the appropriate {@link Arrays#sort(char[]) Arrays.sort}
- * method. If the length of the specified array is less than the minimum
- * granularity, then it is sorted using the appropriate {@link
- * Arrays#sort(char[]) Arrays.sort} method. The algorithm requires a
- * working space no greater than the size of the original array. The
- * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to
- * execute any parallel tasks.
+ * @implNote The sorting algorithm is a Dual-Pivot Quicksort by
+ * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm
+ * offers O(n log(n)) performance on all data sets, and is typically
+ * faster than traditional (one-pivot) Quicksort implementations.
*
* @param a the array to be sorted
*
* @since 1.8
*/
- public static void parallelSort(char[] a) {
- int n = a.length, p, g;
- if (n <= MIN_ARRAY_SORT_GRAN ||
- (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
- DualPivotQuicksort.sort(a, 0, n - 1, null, 0, 0);
- else
- new ArraysParallelSortHelpers.FJChar.Sorter
- (null, a, new char[n], 0, n, 0,
- ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
- MIN_ARRAY_SORT_GRAN : g).invoke();
+ public static void parallelSort(long[] a) {
+ DualPivotQuicksort.sort(a, RUN_IN_PARALLEL, 0, a.length);
}
/**
@@ -550,16 +469,10 @@
* inclusive, to the index {@code toIndex}, exclusive. If
* {@code fromIndex == toIndex}, the range to be sorted is empty.
*
- @implNote The sorting algorithm is a parallel sort-merge that breaks the
- * array into sub-arrays that are themselves sorted and then merged. When
- * the sub-array length reaches a minimum granularity, the sub-array is
- * sorted using the appropriate {@link Arrays#sort(char[]) Arrays.sort}
- * method. If the length of the specified array is less than the minimum
- * granularity, then it is sorted using the appropriate {@link
- * Arrays#sort(char[]) Arrays.sort} method. The algorithm requires a working
- * space no greater than the size of the specified range of the original
- * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is
- * used to execute any parallel tasks.
+ * @implNote The sorting algorithm is a Dual-Pivot Quicksort by
+ * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm
+ * offers O(n log(n)) performance on all data sets, and is typically
+ * faster than traditional (one-pivot) Quicksort implementations.
*
* @param a the array to be sorted
* @param fromIndex the index of the first element, inclusive, to be sorted
@@ -571,47 +484,25 @@
*
* @since 1.8
*/
- public static void parallelSort(char[] a, int fromIndex, int toIndex) {
+ public static void parallelSort(long[] a, int fromIndex, int toIndex) {
rangeCheck(a.length, fromIndex, toIndex);
- int n = toIndex - fromIndex, p, g;
- if (n <= MIN_ARRAY_SORT_GRAN ||
- (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
- DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
- else
- new ArraysParallelSortHelpers.FJChar.Sorter
- (null, a, new char[n], fromIndex, n, 0,
- ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
- MIN_ARRAY_SORT_GRAN : g).invoke();
+ DualPivotQuicksort.sort(a, RUN_IN_PARALLEL, fromIndex, toIndex);
}
/**
* Sorts the specified array into ascending numerical order.
*
- * @implNote The sorting algorithm is a parallel sort-merge that breaks the
- * array into sub-arrays that are themselves sorted and then merged. When
- * the sub-array length reaches a minimum granularity, the sub-array is
- * sorted using the appropriate {@link Arrays#sort(short[]) Arrays.sort}
- * method. If the length of the specified array is less than the minimum
- * granularity, then it is sorted using the appropriate {@link
- * Arrays#sort(short[]) Arrays.sort} method. The algorithm requires a
- * working space no greater than the size of the original array. The
- * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to
- * execute any parallel tasks.
+ * @implNote The sorting algorithm is a Dual-Pivot Quicksort by
+ * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm
+ * offers O(n log(n)) performance on all data sets, and is typically
+ * faster than traditional (one-pivot) Quicksort implementations.
*
* @param a the array to be sorted
*
* @since 1.8
*/
- public static void parallelSort(short[] a) {
- int n = a.length, p, g;
- if (n <= MIN_ARRAY_SORT_GRAN ||
- (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
- DualPivotQuicksort.sort(a, 0, n - 1, null, 0, 0);
- else
- new ArraysParallelSortHelpers.FJShort.Sorter
- (null, a, new short[n], 0, n, 0,
- ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
- MIN_ARRAY_SORT_GRAN : g).invoke();
+ public static void parallelSort(byte[] a) {
+ DualPivotQuicksort.sort(a, RUN_IN_PARALLEL, 0, a.length);
}
/**
@@ -620,16 +511,10 @@
* inclusive, to the index {@code toIndex}, exclusive. If
* {@code fromIndex == toIndex}, the range to be sorted is empty.
*
- * @implNote The sorting algorithm is a parallel sort-merge that breaks the
- * array into sub-arrays that are themselves sorted and then merged. When
- * the sub-array length reaches a minimum granularity, the sub-array is
- * sorted using the appropriate {@link Arrays#sort(short[]) Arrays.sort}
- * method. If the length of the specified array is less than the minimum
- * granularity, then it is sorted using the appropriate {@link
- * Arrays#sort(short[]) Arrays.sort} method. The algorithm requires a working
- * space no greater than the size of the specified range of the original
- * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is
- * used to execute any parallel tasks.
+ * @implNote The sorting algorithm is a Dual-Pivot Quicksort by
+ * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm
+ * offers O(n log(n)) performance on all data sets, and is typically
+ * faster than traditional (one-pivot) Quicksort implementations.
*
* @param a the array to be sorted
* @param fromIndex the index of the first element, inclusive, to be sorted
@@ -641,47 +526,25 @@
*
* @since 1.8
*/
- public static void parallelSort(short[] a, int fromIndex, int toIndex) {
+ public static void parallelSort(byte[] a, int fromIndex, int toIndex) {
rangeCheck(a.length, fromIndex, toIndex);
- int n = toIndex - fromIndex, p, g;
- if (n <= MIN_ARRAY_SORT_GRAN ||
- (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
- DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
- else
- new ArraysParallelSortHelpers.FJShort.Sorter
- (null, a, new short[n], fromIndex, n, 0,
- ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
- MIN_ARRAY_SORT_GRAN : g).invoke();
+ DualPivotQuicksort.sort(a, RUN_IN_PARALLEL, fromIndex, toIndex);
}
/**
* Sorts the specified array into ascending numerical order.
*
- * @implNote The sorting algorithm is a parallel sort-merge that breaks the
- * array into sub-arrays that are themselves sorted and then merged. When
- * the sub-array length reaches a minimum granularity, the sub-array is
- * sorted using the appropriate {@link Arrays#sort(int[]) Arrays.sort}
- * method. If the length of the specified array is less than the minimum
- * granularity, then it is sorted using the appropriate {@link
- * Arrays#sort(int[]) Arrays.sort} method. The algorithm requires a
- * working space no greater than the size of the original array. The
- * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to
- * execute any parallel tasks.
+ * @implNote The sorting algorithm is a Dual-Pivot Quicksort by
+ * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm
+ * offers O(n log(n)) performance on all data sets, and is typically
+ * faster than traditional (one-pivot) Quicksort implementations.
*
* @param a the array to be sorted
*
* @since 1.8
*/
- public static void parallelSort(int[] a) {
- int n = a.length, p, g;
- if (n <= MIN_ARRAY_SORT_GRAN ||
- (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
- DualPivotQuicksort.sort(a, 0, n - 1, null, 0, 0);
- else
- new ArraysParallelSortHelpers.FJInt.Sorter
- (null, a, new int[n], 0, n, 0,
- ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
- MIN_ARRAY_SORT_GRAN : g).invoke();
+ public static void parallelSort(char[] a) {
+ DualPivotQuicksort.sort(a, RUN_IN_PARALLEL, 0, a.length);
}
/**
@@ -690,16 +553,10 @@
* inclusive, to the index {@code toIndex}, exclusive. If
* {@code fromIndex == toIndex}, the range to be sorted is empty.
*
- * @implNote The sorting algorithm is a parallel sort-merge that breaks the
- * array into sub-arrays that are themselves sorted and then merged. When
- * the sub-array length reaches a minimum granularity, the sub-array is
- * sorted using the appropriate {@link Arrays#sort(int[]) Arrays.sort}
- * method. If the length of the specified array is less than the minimum
- * granularity, then it is sorted using the appropriate {@link
- * Arrays#sort(int[]) Arrays.sort} method. The algorithm requires a working
- * space no greater than the size of the specified range of the original
- * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is
- * used to execute any parallel tasks.
+ * @implNote The sorting algorithm is a Dual-Pivot Quicksort by
+ * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm
+ * offers O(n log(n)) performance on all data sets, and is typically
+ * faster than traditional (one-pivot) Quicksort implementations.
*
* @param a the array to be sorted
* @param fromIndex the index of the first element, inclusive, to be sorted
@@ -711,47 +568,25 @@
*
* @since 1.8
*/
- public static void parallelSort(int[] a, int fromIndex, int toIndex) {
+ public static void parallelSort(char[] a, int fromIndex, int toIndex) {
rangeCheck(a.length, fromIndex, toIndex);
- int n = toIndex - fromIndex, p, g;
- if (n <= MIN_ARRAY_SORT_GRAN ||
- (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
- DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
- else
- new ArraysParallelSortHelpers.FJInt.Sorter
- (null, a, new int[n], fromIndex, n, 0,
- ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
- MIN_ARRAY_SORT_GRAN : g).invoke();
+ DualPivotQuicksort.sort(a, RUN_IN_PARALLEL, fromIndex, toIndex);
}
/**
* Sorts the specified array into ascending numerical order.
*
- * @implNote The sorting algorithm is a parallel sort-merge that breaks the
- * array into sub-arrays that are themselves sorted and then merged. When
- * the sub-array length reaches a minimum granularity, the sub-array is
- * sorted using the appropriate {@link Arrays#sort(long[]) Arrays.sort}
- * method. If the length of the specified array is less than the minimum
- * granularity, then it is sorted using the appropriate {@link
- * Arrays#sort(long[]) Arrays.sort} method. The algorithm requires a
- * working space no greater than the size of the original array. The
- * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to
- * execute any parallel tasks.
+ * @implNote The sorting algorithm is a Dual-Pivot Quicksort by
+ * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm
+ * offers O(n log(n)) performance on all data sets, and is typically
+ * faster than traditional (one-pivot) Quicksort implementations.
*
* @param a the array to be sorted
*
* @since 1.8
*/
- public static void parallelSort(long[] a) {
- int n = a.length, p, g;
- if (n <= MIN_ARRAY_SORT_GRAN ||
- (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
- DualPivotQuicksort.sort(a, 0, n - 1, null, 0, 0);
- else
- new ArraysParallelSortHelpers.FJLong.Sorter
- (null, a, new long[n], 0, n, 0,
- ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
- MIN_ARRAY_SORT_GRAN : g).invoke();
+ public static void parallelSort(short[] a) {
+ DualPivotQuicksort.sort(a, RUN_IN_PARALLEL, 0, a.length);
}
/**
@@ -760,16 +595,10 @@
* inclusive, to the index {@code toIndex}, exclusive. If
* {@code fromIndex == toIndex}, the range to be sorted is empty.
*
- * @implNote The sorting algorithm is a parallel sort-merge that breaks the
- * array into sub-arrays that are themselves sorted and then merged. When
- * the sub-array length reaches a minimum granularity, the sub-array is
- * sorted using the appropriate {@link Arrays#sort(long[]) Arrays.sort}
- * method. If the length of the specified array is less than the minimum
- * granularity, then it is sorted using the appropriate {@link
- * Arrays#sort(long[]) Arrays.sort} method. The algorithm requires a working
- * space no greater than the size of the specified range of the original
- * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is
- * used to execute any parallel tasks.
+ * @implNote The sorting algorithm is a Dual-Pivot Quicksort by
+ * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm
+ * offers O(n log(n)) performance on all data sets, and is typically
+ * faster than traditional (one-pivot) Quicksort implementations.
*
* @param a the array to be sorted
* @param fromIndex the index of the first element, inclusive, to be sorted
@@ -781,17 +610,9 @@
*
* @since 1.8
*/
- public static void parallelSort(long[] a, int fromIndex, int toIndex) {
+ public static void parallelSort(short[] a, int fromIndex, int toIndex) {
rangeCheck(a.length, fromIndex, toIndex);
- int n = toIndex - fromIndex, p, g;
- if (n <= MIN_ARRAY_SORT_GRAN ||
- (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
- DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
- else
- new ArraysParallelSortHelpers.FJLong.Sorter
- (null, a, new long[n], fromIndex, n, 0,
- ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
- MIN_ARRAY_SORT_GRAN : g).invoke();
+ DualPivotQuicksort.sort(a, RUN_IN_PARALLEL, fromIndex, toIndex);
}
/**
@@ -805,31 +626,17 @@
* {@code 0.0f} and {@code Float.NaN} is considered greater than any
* other value and all {@code Float.NaN} values are considered equal.
*
- * @implNote The sorting algorithm is a parallel sort-merge that breaks the
- * array into sub-arrays that are themselves sorted and then merged. When
- * the sub-array length reaches a minimum granularity, the sub-array is
- * sorted using the appropriate {@link Arrays#sort(float[]) Arrays.sort}
- * method. If the length of the specified array is less than the minimum
- * granularity, then it is sorted using the appropriate {@link
- * Arrays#sort(float[]) Arrays.sort} method. The algorithm requires a
- * working space no greater than the size of the original array. The
- * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to
- * execute any parallel tasks.
+ * @implNote The sorting algorithm is a Dual-Pivot Quicksort by
+ * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm
+ * offers O(n log(n)) performance on all data sets, and is typically
+ * faster than traditional (one-pivot) Quicksort implementations.
*
* @param a the array to be sorted
*
* @since 1.8
*/
public static void parallelSort(float[] a) {
- int n = a.length, p, g;
- if (n <= MIN_ARRAY_SORT_GRAN ||
- (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
- DualPivotQuicksort.sort(a, 0, n - 1, null, 0, 0);
- else
- new ArraysParallelSortHelpers.FJFloat.Sorter
- (null, a, new float[n], 0, n, 0,
- ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
- MIN_ARRAY_SORT_GRAN : g).invoke();
+ DualPivotQuicksort.sort(a, RUN_IN_PARALLEL, 0, a.length);
}
/**
@@ -846,16 +653,10 @@
* {@code 0.0f} and {@code Float.NaN} is considered greater than any
* other value and all {@code Float.NaN} values are considered equal.
*
- * @implNote The sorting algorithm is a parallel sort-merge that breaks the
- * array into sub-arrays that are themselves sorted and then merged. When
- * the sub-array length reaches a minimum granularity, the sub-array is
- * sorted using the appropriate {@link Arrays#sort(float[]) Arrays.sort}
- * method. If the length of the specified array is less than the minimum
- * granularity, then it is sorted using the appropriate {@link
- * Arrays#sort(float[]) Arrays.sort} method. The algorithm requires a working
- * space no greater than the size of the specified range of the original
- * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is
- * used to execute any parallel tasks.
+ * @implNote The sorting algorithm is a Dual-Pivot Quicksort by
+ * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm
+ * offers O(n log(n)) performance on all data sets, and is typically
+ * faster than traditional (one-pivot) Quicksort implementations.
*
* @param a the array to be sorted
* @param fromIndex the index of the first element, inclusive, to be sorted
@@ -869,15 +670,7 @@
*/
public static void parallelSort(float[] a, int fromIndex, int toIndex) {
rangeCheck(a.length, fromIndex, toIndex);
- int n = toIndex - fromIndex, p, g;
- if (n <= MIN_ARRAY_SORT_GRAN ||
- (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
- DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
- else
- new ArraysParallelSortHelpers.FJFloat.Sorter
- (null, a, new float[n], fromIndex, n, 0,
- ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
- MIN_ARRAY_SORT_GRAN : g).invoke();
+ DualPivotQuicksort.sort(a, RUN_IN_PARALLEL, fromIndex, toIndex);
}
/**
@@ -891,31 +684,17 @@
* {@code 0.0d} and {@code Double.NaN} is considered greater than any
* other value and all {@code Double.NaN} values are considered equal.
*
- * @implNote The sorting algorithm is a parallel sort-merge that breaks the
- * array into sub-arrays that are themselves sorted and then merged. When
- * the sub-array length reaches a minimum granularity, the sub-array is
- * sorted using the appropriate {@link Arrays#sort(double[]) Arrays.sort}
- * method. If the length of the specified array is less than the minimum
- * granularity, then it is sorted using the appropriate {@link
- * Arrays#sort(double[]) Arrays.sort} method. The algorithm requires a
- * working space no greater than the size of the original array. The
- * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to
- * execute any parallel tasks.
+ * @implNote The sorting algorithm is a Dual-Pivot Quicksort by
+ * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm
+ * offers O(n log(n)) performance on all data sets, and is typically
+ * faster than traditional (one-pivot) Quicksort implementations.
*
* @param a the array to be sorted
*
* @since 1.8
*/
public static void parallelSort(double[] a) {
- int n = a.length, p, g;
- if (n <= MIN_ARRAY_SORT_GRAN ||
- (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
- DualPivotQuicksort.sort(a, 0, n - 1, null, 0, 0);
- else
- new ArraysParallelSortHelpers.FJDouble.Sorter
- (null, a, new double[n], 0, n, 0,
- ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
- MIN_ARRAY_SORT_GRAN : g).invoke();
+ DualPivotQuicksort.sort(a, RUN_IN_PARALLEL, 0, a.length);
}
/**
@@ -932,16 +711,10 @@
* {@code 0.0d} and {@code Double.NaN} is considered greater than any
* other value and all {@code Double.NaN} values are considered equal.
*
- * @implNote The sorting algorithm is a parallel sort-merge that breaks the
- * array into sub-arrays that are themselves sorted and then merged. When
- * the sub-array length reaches a minimum granularity, the sub-array is
- * sorted using the appropriate {@link Arrays#sort(double[]) Arrays.sort}
- * method. If the length of the specified array is less than the minimum
- * granularity, then it is sorted using the appropriate {@link
- * Arrays#sort(double[]) Arrays.sort} method. The algorithm requires a working
- * space no greater than the size of the specified range of the original
- * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is
- * used to execute any parallel tasks.
+ * @implNote The sorting algorithm is a Dual-Pivot Quicksort by
+ * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm
+ * offers O(n log(n)) performance on all data sets, and is typically
+ * faster than traditional (one-pivot) Quicksort implementations.
*
* @param a the array to be sorted
* @param fromIndex the index of the first element, inclusive, to be sorted
@@ -955,18 +728,41 @@
*/
public static void parallelSort(double[] a, int fromIndex, int toIndex) {
rangeCheck(a.length, fromIndex, toIndex);
- int n = toIndex - fromIndex, p, g;
- if (n <= MIN_ARRAY_SORT_GRAN ||
- (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
- DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
- else
- new ArraysParallelSortHelpers.FJDouble.Sorter
- (null, a, new double[n], fromIndex, n, 0,
- ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
- MIN_ARRAY_SORT_GRAN : g).invoke();
+ DualPivotQuicksort.sort(a, RUN_IN_PARALLEL, fromIndex, toIndex);
}
/**
+ * A comparator that implements the natural ordering of a group of
+ * mutually comparable elements. May be used when a supplied
+ * comparator is null. To simplify code-sharing within underlying
+ * implementations, the compare method only declares type Object
+ * for its second argument.
+ *
+ * Arrays class implementor's note: It is an empirical matter
+ * whether ComparableTimSort offers any performance benefit over
+ * TimSort used with this comparator. If not, you are better off
+ * deleting or bypassing ComparableTimSort. There is currently no
+ * empirical case for separating them for parallel sorting, so all
+ * public Object parallelSort methods use the same comparator
+ * based implementation.
+ */
+ static final class NaturalOrder implements Comparator {
+ @SuppressWarnings("unchecked")
+ public int compare(Object first, Object second) {
+ return ((Comparable)first).compareTo(second);
+ }
+ static final NaturalOrder INSTANCE = new NaturalOrder();
+ }
+
+ /**
+ * The minimum array length below which a parallel sorting
+ * algorithm will not further partition the sorting task. Using
+ * smaller sizes typically results in memory contention across
+ * tasks that makes parallel speedups unlikely.
+ */
+ private static final int MIN_ARRAY_SORT_GRAN = 1 << 13;
+
+ /**
* Sorts the specified array of objects into ascending order, according
* to the {@linkplain Comparable natural ordering} of its elements.
* All elements in the array must implement the {@link Comparable}
--- old/src/java.base/share/classes/java/util/ArraysParallelSortHelpers.java 2018-01-18 06:09:09.829862962 -0800
+++ new/src/java.base/share/classes/java/util/ArraysParallelSortHelpers.java 2018-01-18 06:09:09.322815910 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -36,7 +36,7 @@
* Sorter classes based mainly on CilkSort
* Cilk :
* Basic algorithm:
- * if array size is small, just use a sequential quicksort (via Arrays.sort)
+ * if array size is small, just use a sequential sort (via Arrays.sort)
* Otherwise:
* 1. Break array in half.
* 2. For each half,
@@ -46,31 +46,27 @@
* 3. merge together the two halves.
*
* One reason for splitting in quarters is that this guarantees that
- * the final sort is in the main array, not the workspace array.
- * (workspace and main swap roles on each subsort step.) Leaf-level
+ * the final sort is in the main array, not the workspace array
+ * (workspace and main swap roles on each subsort step). Leaf-level
* sorts use the associated sequential sort.
*
- * Merger classes perform merging for Sorter. They are structured
+ * Merger classes perform merging for Sorter. They are structured
* such that if the underlying sort is stable (as is true for
- * TimSort), then so is the full sort. If big enough, they split the
+ * TimSort), then so is the full sort. If big enough, they split the
* largest of the two partitions in half, find the greatest point in
* smaller partition less than the beginning of the second half of
* larger via binary search; and then merge in parallel the two
- * partitions. In part to ensure tasks are triggered in
+ * partitions. In part to ensure tasks are triggered in
* stability-preserving order, the current CountedCompleter design
* requires some little tasks to serve as place holders for triggering
- * completion tasks. These classes (EmptyCompleter and Relay) don't
+ * completion tasks. These classes (EmptyCompleter and Relay) don't
* need to keep track of the arrays, and are never themselves forked,
* so don't hold any task state.
*
- * The primitive class versions (FJByte... FJDouble) are
- * identical to each other except for type declarations.
- *
* The base sequential sorts rely on non-public versions of TimSort,
- * ComparableTimSort, and DualPivotQuicksort sort methods that accept
- * temp workspace array slices that we will have already allocated, so
- * avoids redundant allocation. (Except for DualPivotQuicksort byte[]
- * sort, that does not ever use a workspace array.)
+ * ComparableTimSort sort methods that accept temp workspace array
+ * slices that we will have already allocated, so avoids redundant
+ * allocation.
*/
/*package*/ class ArraysParallelSortHelpers {
@@ -226,785 +222,6 @@
tryComplete();
}
-
- }
- } // FJObject
-
- /** byte support class */
- static final class FJByte {
- static final class Sorter extends CountedCompleter {
- static final long serialVersionUID = 2446542900576103244L;
- final byte[] a, w;
- final int base, size, wbase, gran;
- Sorter(CountedCompleter> par, byte[] a, byte[] w, int base,
- int size, int wbase, int gran) {
- super(par);
- this.a = a; this.w = w; this.base = base; this.size = size;
- this.wbase = wbase; this.gran = gran;
- }
- public final void compute() {
- CountedCompleter> s = this;
- byte[] a = this.a, w = this.w; // localize all params
- int b = this.base, n = this.size, wb = this.wbase, g = this.gran;
- while (n > g) {
- int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles
- Relay fc = new Relay(new Merger(s, w, a, wb, h,
- wb+h, n-h, b, g));
- Relay rc = new Relay(new Merger(fc, a, w, b+h, q,
- b+u, n-u, wb+h, g));
- new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork();
- new Sorter(rc, a, w, b+h, q, wb+h, g).fork();;
- Relay bc = new Relay(new Merger(fc, a, w, b, q,
- b+q, h-q, wb, g));
- new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork();
- s = new EmptyCompleter(bc);
- n = q;
- }
- DualPivotQuicksort.sort(a, b, b + n - 1);
- s.tryComplete();
- }
- }
-
- static final class Merger extends CountedCompleter {
- static final long serialVersionUID = 2446542900576103244L;
- final byte[] a, w; // main and workspace arrays
- final int lbase, lsize, rbase, rsize, wbase, gran;
- Merger(CountedCompleter> par, byte[] a, byte[] w,
- int lbase, int lsize, int rbase,
- int rsize, int wbase, int gran) {
- super(par);
- this.a = a; this.w = w;
- this.lbase = lbase; this.lsize = lsize;
- this.rbase = rbase; this.rsize = rsize;
- this.wbase = wbase; this.gran = gran;
- }
-
- public final void compute() {
- byte[] a = this.a, w = this.w; // localize all params
- int lb = this.lbase, ln = this.lsize, rb = this.rbase,
- rn = this.rsize, k = this.wbase, g = this.gran;
- if (a == null || w == null || lb < 0 || rb < 0 || k < 0)
- throw new IllegalStateException(); // hoist checks
- for (int lh, rh;;) { // split larger, find point in smaller
- if (ln >= rn) {
- if (ln <= g)
- break;
- rh = rn;
- byte split = a[(lh = ln >>> 1) + lb];
- for (int lo = 0; lo < rh; ) {
- int rm = (lo + rh) >>> 1;
- if (split <= a[rm + rb])
- rh = rm;
- else
- lo = rm + 1;
- }
- }
- else {
- if (rn <= g)
- break;
- lh = ln;
- byte split = a[(rh = rn >>> 1) + rb];
- for (int lo = 0; lo < lh; ) {
- int lm = (lo + lh) >>> 1;
- if (split <= a[lm + lb])
- lh = lm;
- else
- lo = lm + 1;
- }
- }
- Merger m = new Merger(this, a, w, lb + lh, ln - lh,
- rb + rh, rn - rh,
- k + lh + rh, g);
- rn = rh;
- ln = lh;
- addToPendingCount(1);
- m.fork();
- }
-
- int lf = lb + ln, rf = rb + rn; // index bounds
- while (lb < lf && rb < rf) {
- byte t, al, ar;
- if ((al = a[lb]) <= (ar = a[rb])) {
- lb++; t = al;
- }
- else {
- rb++; t = ar;
- }
- w[k++] = t;
- }
- if (rb < rf)
- System.arraycopy(a, rb, w, k, rf - rb);
- else if (lb < lf)
- System.arraycopy(a, lb, w, k, lf - lb);
- tryComplete();
- }
- }
- } // FJByte
-
- /** char support class */
- static final class FJChar {
- static final class Sorter extends CountedCompleter {
- static final long serialVersionUID = 2446542900576103244L;
- final char[] a, w;
- final int base, size, wbase, gran;
- Sorter(CountedCompleter> par, char[] a, char[] w, int base,
- int size, int wbase, int gran) {
- super(par);
- this.a = a; this.w = w; this.base = base; this.size = size;
- this.wbase = wbase; this.gran = gran;
- }
- public final void compute() {
- CountedCompleter> s = this;
- char[] a = this.a, w = this.w; // localize all params
- int b = this.base, n = this.size, wb = this.wbase, g = this.gran;
- while (n > g) {
- int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles
- Relay fc = new Relay(new Merger(s, w, a, wb, h,
- wb+h, n-h, b, g));
- Relay rc = new Relay(new Merger(fc, a, w, b+h, q,
- b+u, n-u, wb+h, g));
- new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork();
- new Sorter(rc, a, w, b+h, q, wb+h, g).fork();;
- Relay bc = new Relay(new Merger(fc, a, w, b, q,
- b+q, h-q, wb, g));
- new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork();
- s = new EmptyCompleter(bc);
- n = q;
- }
- DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n);
- s.tryComplete();
- }
- }
-
- static final class Merger extends CountedCompleter {
- static final long serialVersionUID = 2446542900576103244L;
- final char[] a, w; // main and workspace arrays
- final int lbase, lsize, rbase, rsize, wbase, gran;
- Merger(CountedCompleter> par, char[] a, char[] w,
- int lbase, int lsize, int rbase,
- int rsize, int wbase, int gran) {
- super(par);
- this.a = a; this.w = w;
- this.lbase = lbase; this.lsize = lsize;
- this.rbase = rbase; this.rsize = rsize;
- this.wbase = wbase; this.gran = gran;
- }
-
- public final void compute() {
- char[] a = this.a, w = this.w; // localize all params
- int lb = this.lbase, ln = this.lsize, rb = this.rbase,
- rn = this.rsize, k = this.wbase, g = this.gran;
- if (a == null || w == null || lb < 0 || rb < 0 || k < 0)
- throw new IllegalStateException(); // hoist checks
- for (int lh, rh;;) { // split larger, find point in smaller
- if (ln >= rn) {
- if (ln <= g)
- break;
- rh = rn;
- char split = a[(lh = ln >>> 1) + lb];
- for (int lo = 0; lo < rh; ) {
- int rm = (lo + rh) >>> 1;
- if (split <= a[rm + rb])
- rh = rm;
- else
- lo = rm + 1;
- }
- }
- else {
- if (rn <= g)
- break;
- lh = ln;
- char split = a[(rh = rn >>> 1) + rb];
- for (int lo = 0; lo < lh; ) {
- int lm = (lo + lh) >>> 1;
- if (split <= a[lm + lb])
- lh = lm;
- else
- lo = lm + 1;
- }
- }
- Merger m = new Merger(this, a, w, lb + lh, ln - lh,
- rb + rh, rn - rh,
- k + lh + rh, g);
- rn = rh;
- ln = lh;
- addToPendingCount(1);
- m.fork();
- }
-
- int lf = lb + ln, rf = rb + rn; // index bounds
- while (lb < lf && rb < rf) {
- char t, al, ar;
- if ((al = a[lb]) <= (ar = a[rb])) {
- lb++; t = al;
- }
- else {
- rb++; t = ar;
- }
- w[k++] = t;
- }
- if (rb < rf)
- System.arraycopy(a, rb, w, k, rf - rb);
- else if (lb < lf)
- System.arraycopy(a, lb, w, k, lf - lb);
- tryComplete();
- }
- }
- } // FJChar
-
- /** short support class */
- static final class FJShort {
- static final class Sorter extends CountedCompleter {
- static final long serialVersionUID = 2446542900576103244L;
- final short[] a, w;
- final int base, size, wbase, gran;
- Sorter(CountedCompleter> par, short[] a, short[] w, int base,
- int size, int wbase, int gran) {
- super(par);
- this.a = a; this.w = w; this.base = base; this.size = size;
- this.wbase = wbase; this.gran = gran;
- }
- public final void compute() {
- CountedCompleter> s = this;
- short[] a = this.a, w = this.w; // localize all params
- int b = this.base, n = this.size, wb = this.wbase, g = this.gran;
- while (n > g) {
- int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles
- Relay fc = new Relay(new Merger(s, w, a, wb, h,
- wb+h, n-h, b, g));
- Relay rc = new Relay(new Merger(fc, a, w, b+h, q,
- b+u, n-u, wb+h, g));
- new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork();
- new Sorter(rc, a, w, b+h, q, wb+h, g).fork();;
- Relay bc = new Relay(new Merger(fc, a, w, b, q,
- b+q, h-q, wb, g));
- new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork();
- s = new EmptyCompleter(bc);
- n = q;
- }
- DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n);
- s.tryComplete();
- }
- }
-
- static final class Merger extends CountedCompleter {
- static final long serialVersionUID = 2446542900576103244L;
- final short[] a, w; // main and workspace arrays
- final int lbase, lsize, rbase, rsize, wbase, gran;
- Merger(CountedCompleter> par, short[] a, short[] w,
- int lbase, int lsize, int rbase,
- int rsize, int wbase, int gran) {
- super(par);
- this.a = a; this.w = w;
- this.lbase = lbase; this.lsize = lsize;
- this.rbase = rbase; this.rsize = rsize;
- this.wbase = wbase; this.gran = gran;
- }
-
- public final void compute() {
- short[] a = this.a, w = this.w; // localize all params
- int lb = this.lbase, ln = this.lsize, rb = this.rbase,
- rn = this.rsize, k = this.wbase, g = this.gran;
- if (a == null || w == null || lb < 0 || rb < 0 || k < 0)
- throw new IllegalStateException(); // hoist checks
- for (int lh, rh;;) { // split larger, find point in smaller
- if (ln >= rn) {
- if (ln <= g)
- break;
- rh = rn;
- short split = a[(lh = ln >>> 1) + lb];
- for (int lo = 0; lo < rh; ) {
- int rm = (lo + rh) >>> 1;
- if (split <= a[rm + rb])
- rh = rm;
- else
- lo = rm + 1;
- }
- }
- else {
- if (rn <= g)
- break;
- lh = ln;
- short split = a[(rh = rn >>> 1) + rb];
- for (int lo = 0; lo < lh; ) {
- int lm = (lo + lh) >>> 1;
- if (split <= a[lm + lb])
- lh = lm;
- else
- lo = lm + 1;
- }
- }
- Merger m = new Merger(this, a, w, lb + lh, ln - lh,
- rb + rh, rn - rh,
- k + lh + rh, g);
- rn = rh;
- ln = lh;
- addToPendingCount(1);
- m.fork();
- }
-
- int lf = lb + ln, rf = rb + rn; // index bounds
- while (lb < lf && rb < rf) {
- short t, al, ar;
- if ((al = a[lb]) <= (ar = a[rb])) {
- lb++; t = al;
- }
- else {
- rb++; t = ar;
- }
- w[k++] = t;
- }
- if (rb < rf)
- System.arraycopy(a, rb, w, k, rf - rb);
- else if (lb < lf)
- System.arraycopy(a, lb, w, k, lf - lb);
- tryComplete();
- }
- }
- } // FJShort
-
- /** int support class */
- static final class FJInt {
- static final class Sorter extends CountedCompleter {
- static final long serialVersionUID = 2446542900576103244L;
- final int[] a, w;
- final int base, size, wbase, gran;
- Sorter(CountedCompleter> par, int[] a, int[] w, int base,
- int size, int wbase, int gran) {
- super(par);
- this.a = a; this.w = w; this.base = base; this.size = size;
- this.wbase = wbase; this.gran = gran;
- }
- public final void compute() {
- CountedCompleter> s = this;
- int[] a = this.a, w = this.w; // localize all params
- int b = this.base, n = this.size, wb = this.wbase, g = this.gran;
- while (n > g) {
- int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles
- Relay fc = new Relay(new Merger(s, w, a, wb, h,
- wb+h, n-h, b, g));
- Relay rc = new Relay(new Merger(fc, a, w, b+h, q,
- b+u, n-u, wb+h, g));
- new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork();
- new Sorter(rc, a, w, b+h, q, wb+h, g).fork();;
- Relay bc = new Relay(new Merger(fc, a, w, b, q,
- b+q, h-q, wb, g));
- new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork();
- s = new EmptyCompleter(bc);
- n = q;
- }
- DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n);
- s.tryComplete();
- }
}
-
- static final class Merger extends CountedCompleter {
- static final long serialVersionUID = 2446542900576103244L;
- final int[] a, w; // main and workspace arrays
- final int lbase, lsize, rbase, rsize, wbase, gran;
- Merger(CountedCompleter> par, int[] a, int[] w,
- int lbase, int lsize, int rbase,
- int rsize, int wbase, int gran) {
- super(par);
- this.a = a; this.w = w;
- this.lbase = lbase; this.lsize = lsize;
- this.rbase = rbase; this.rsize = rsize;
- this.wbase = wbase; this.gran = gran;
- }
-
- public final void compute() {
- int[] a = this.a, w = this.w; // localize all params
- int lb = this.lbase, ln = this.lsize, rb = this.rbase,
- rn = this.rsize, k = this.wbase, g = this.gran;
- if (a == null || w == null || lb < 0 || rb < 0 || k < 0)
- throw new IllegalStateException(); // hoist checks
- for (int lh, rh;;) { // split larger, find point in smaller
- if (ln >= rn) {
- if (ln <= g)
- break;
- rh = rn;
- int split = a[(lh = ln >>> 1) + lb];
- for (int lo = 0; lo < rh; ) {
- int rm = (lo + rh) >>> 1;
- if (split <= a[rm + rb])
- rh = rm;
- else
- lo = rm + 1;
- }
- }
- else {
- if (rn <= g)
- break;
- lh = ln;
- int split = a[(rh = rn >>> 1) + rb];
- for (int lo = 0; lo < lh; ) {
- int lm = (lo + lh) >>> 1;
- if (split <= a[lm + lb])
- lh = lm;
- else
- lo = lm + 1;
- }
- }
- Merger m = new Merger(this, a, w, lb + lh, ln - lh,
- rb + rh, rn - rh,
- k + lh + rh, g);
- rn = rh;
- ln = lh;
- addToPendingCount(1);
- m.fork();
- }
-
- int lf = lb + ln, rf = rb + rn; // index bounds
- while (lb < lf && rb < rf) {
- int t, al, ar;
- if ((al = a[lb]) <= (ar = a[rb])) {
- lb++; t = al;
- }
- else {
- rb++; t = ar;
- }
- w[k++] = t;
- }
- if (rb < rf)
- System.arraycopy(a, rb, w, k, rf - rb);
- else if (lb < lf)
- System.arraycopy(a, lb, w, k, lf - lb);
- tryComplete();
- }
- }
- } // FJInt
-
- /** long support class */
- static final class FJLong {
- static final class Sorter extends CountedCompleter {
- static final long serialVersionUID = 2446542900576103244L;
- final long[] a, w;
- final int base, size, wbase, gran;
- Sorter(CountedCompleter> par, long[] a, long[] w, int base,
- int size, int wbase, int gran) {
- super(par);
- this.a = a; this.w = w; this.base = base; this.size = size;
- this.wbase = wbase; this.gran = gran;
- }
- public final void compute() {
- CountedCompleter> s = this;
- long[] a = this.a, w = this.w; // localize all params
- int b = this.base, n = this.size, wb = this.wbase, g = this.gran;
- while (n > g) {
- int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles
- Relay fc = new Relay(new Merger(s, w, a, wb, h,
- wb+h, n-h, b, g));
- Relay rc = new Relay(new Merger(fc, a, w, b+h, q,
- b+u, n-u, wb+h, g));
- new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork();
- new Sorter(rc, a, w, b+h, q, wb+h, g).fork();;
- Relay bc = new Relay(new Merger(fc, a, w, b, q,
- b+q, h-q, wb, g));
- new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork();
- s = new EmptyCompleter(bc);
- n = q;
- }
- DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n);
- s.tryComplete();
- }
- }
-
- static final class Merger extends CountedCompleter {
- static final long serialVersionUID = 2446542900576103244L;
- final long[] a, w; // main and workspace arrays
- final int lbase, lsize, rbase, rsize, wbase, gran;
- Merger(CountedCompleter> par, long[] a, long[] w,
- int lbase, int lsize, int rbase,
- int rsize, int wbase, int gran) {
- super(par);
- this.a = a; this.w = w;
- this.lbase = lbase; this.lsize = lsize;
- this.rbase = rbase; this.rsize = rsize;
- this.wbase = wbase; this.gran = gran;
- }
-
- public final void compute() {
- long[] a = this.a, w = this.w; // localize all params
- int lb = this.lbase, ln = this.lsize, rb = this.rbase,
- rn = this.rsize, k = this.wbase, g = this.gran;
- if (a == null || w == null || lb < 0 || rb < 0 || k < 0)
- throw new IllegalStateException(); // hoist checks
- for (int lh, rh;;) { // split larger, find point in smaller
- if (ln >= rn) {
- if (ln <= g)
- break;
- rh = rn;
- long split = a[(lh = ln >>> 1) + lb];
- for (int lo = 0; lo < rh; ) {
- int rm = (lo + rh) >>> 1;
- if (split <= a[rm + rb])
- rh = rm;
- else
- lo = rm + 1;
- }
- }
- else {
- if (rn <= g)
- break;
- lh = ln;
- long split = a[(rh = rn >>> 1) + rb];
- for (int lo = 0; lo < lh; ) {
- int lm = (lo + lh) >>> 1;
- if (split <= a[lm + lb])
- lh = lm;
- else
- lo = lm + 1;
- }
- }
- Merger m = new Merger(this, a, w, lb + lh, ln - lh,
- rb + rh, rn - rh,
- k + lh + rh, g);
- rn = rh;
- ln = lh;
- addToPendingCount(1);
- m.fork();
- }
-
- int lf = lb + ln, rf = rb + rn; // index bounds
- while (lb < lf && rb < rf) {
- long t, al, ar;
- if ((al = a[lb]) <= (ar = a[rb])) {
- lb++; t = al;
- }
- else {
- rb++; t = ar;
- }
- w[k++] = t;
- }
- if (rb < rf)
- System.arraycopy(a, rb, w, k, rf - rb);
- else if (lb < lf)
- System.arraycopy(a, lb, w, k, lf - lb);
- tryComplete();
- }
- }
- } // FJLong
-
- /** float support class */
- static final class FJFloat {
- static final class Sorter extends CountedCompleter {
- static final long serialVersionUID = 2446542900576103244L;
- final float[] a, w;
- final int base, size, wbase, gran;
- Sorter(CountedCompleter> par, float[] a, float[] w, int base,
- int size, int wbase, int gran) {
- super(par);
- this.a = a; this.w = w; this.base = base; this.size = size;
- this.wbase = wbase; this.gran = gran;
- }
- public final void compute() {
- CountedCompleter> s = this;
- float[] a = this.a, w = this.w; // localize all params
- int b = this.base, n = this.size, wb = this.wbase, g = this.gran;
- while (n > g) {
- int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles
- Relay fc = new Relay(new Merger(s, w, a, wb, h,
- wb+h, n-h, b, g));
- Relay rc = new Relay(new Merger(fc, a, w, b+h, q,
- b+u, n-u, wb+h, g));
- new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork();
- new Sorter(rc, a, w, b+h, q, wb+h, g).fork();;
- Relay bc = new Relay(new Merger(fc, a, w, b, q,
- b+q, h-q, wb, g));
- new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork();
- s = new EmptyCompleter(bc);
- n = q;
- }
- DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n);
- s.tryComplete();
- }
- }
-
- static final class Merger extends CountedCompleter {
- static final long serialVersionUID = 2446542900576103244L;
- final float[] a, w; // main and workspace arrays
- final int lbase, lsize, rbase, rsize, wbase, gran;
- Merger(CountedCompleter> par, float[] a, float[] w,
- int lbase, int lsize, int rbase,
- int rsize, int wbase, int gran) {
- super(par);
- this.a = a; this.w = w;
- this.lbase = lbase; this.lsize = lsize;
- this.rbase = rbase; this.rsize = rsize;
- this.wbase = wbase; this.gran = gran;
- }
-
- public final void compute() {
- float[] a = this.a, w = this.w; // localize all params
- int lb = this.lbase, ln = this.lsize, rb = this.rbase,
- rn = this.rsize, k = this.wbase, g = this.gran;
- if (a == null || w == null || lb < 0 || rb < 0 || k < 0)
- throw new IllegalStateException(); // hoist checks
- for (int lh, rh;;) { // split larger, find point in smaller
- if (ln >= rn) {
- if (ln <= g)
- break;
- rh = rn;
- float split = a[(lh = ln >>> 1) + lb];
- for (int lo = 0; lo < rh; ) {
- int rm = (lo + rh) >>> 1;
- if (split <= a[rm + rb])
- rh = rm;
- else
- lo = rm + 1;
- }
- }
- else {
- if (rn <= g)
- break;
- lh = ln;
- float split = a[(rh = rn >>> 1) + rb];
- for (int lo = 0; lo < lh; ) {
- int lm = (lo + lh) >>> 1;
- if (split <= a[lm + lb])
- lh = lm;
- else
- lo = lm + 1;
- }
- }
- Merger m = new Merger(this, a, w, lb + lh, ln - lh,
- rb + rh, rn - rh,
- k + lh + rh, g);
- rn = rh;
- ln = lh;
- addToPendingCount(1);
- m.fork();
- }
-
- int lf = lb + ln, rf = rb + rn; // index bounds
- while (lb < lf && rb < rf) {
- float t, al, ar;
- if ((al = a[lb]) <= (ar = a[rb])) {
- lb++; t = al;
- }
- else {
- rb++; t = ar;
- }
- w[k++] = t;
- }
- if (rb < rf)
- System.arraycopy(a, rb, w, k, rf - rb);
- else if (lb < lf)
- System.arraycopy(a, lb, w, k, lf - lb);
- tryComplete();
- }
- }
- } // FJFloat
-
- /** double support class */
- static final class FJDouble {
- static final class Sorter extends CountedCompleter {
- static final long serialVersionUID = 2446542900576103244L;
- final double[] a, w;
- final int base, size, wbase, gran;
- Sorter(CountedCompleter> par, double[] a, double[] w, int base,
- int size, int wbase, int gran) {
- super(par);
- this.a = a; this.w = w; this.base = base; this.size = size;
- this.wbase = wbase; this.gran = gran;
- }
- public final void compute() {
- CountedCompleter> s = this;
- double[] a = this.a, w = this.w; // localize all params
- int b = this.base, n = this.size, wb = this.wbase, g = this.gran;
- while (n > g) {
- int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles
- Relay fc = new Relay(new Merger(s, w, a, wb, h,
- wb+h, n-h, b, g));
- Relay rc = new Relay(new Merger(fc, a, w, b+h, q,
- b+u, n-u, wb+h, g));
- new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork();
- new Sorter(rc, a, w, b+h, q, wb+h, g).fork();;
- Relay bc = new Relay(new Merger(fc, a, w, b, q,
- b+q, h-q, wb, g));
- new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork();
- s = new EmptyCompleter(bc);
- n = q;
- }
- DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n);
- s.tryComplete();
- }
- }
-
- static final class Merger extends CountedCompleter {
- static final long serialVersionUID = 2446542900576103244L;
- final double[] a, w; // main and workspace arrays
- final int lbase, lsize, rbase, rsize, wbase, gran;
- Merger(CountedCompleter> par, double[] a, double[] w,
- int lbase, int lsize, int rbase,
- int rsize, int wbase, int gran) {
- super(par);
- this.a = a; this.w = w;
- this.lbase = lbase; this.lsize = lsize;
- this.rbase = rbase; this.rsize = rsize;
- this.wbase = wbase; this.gran = gran;
- }
-
- public final void compute() {
- double[] a = this.a, w = this.w; // localize all params
- int lb = this.lbase, ln = this.lsize, rb = this.rbase,
- rn = this.rsize, k = this.wbase, g = this.gran;
- if (a == null || w == null || lb < 0 || rb < 0 || k < 0)
- throw new IllegalStateException(); // hoist checks
- for (int lh, rh;;) { // split larger, find point in smaller
- if (ln >= rn) {
- if (ln <= g)
- break;
- rh = rn;
- double split = a[(lh = ln >>> 1) + lb];
- for (int lo = 0; lo < rh; ) {
- int rm = (lo + rh) >>> 1;
- if (split <= a[rm + rb])
- rh = rm;
- else
- lo = rm + 1;
- }
- }
- else {
- if (rn <= g)
- break;
- lh = ln;
- double split = a[(rh = rn >>> 1) + rb];
- for (int lo = 0; lo < lh; ) {
- int lm = (lo + lh) >>> 1;
- if (split <= a[lm + lb])
- lh = lm;
- else
- lo = lm + 1;
- }
- }
- Merger m = new Merger(this, a, w, lb + lh, ln - lh,
- rb + rh, rn - rh,
- k + lh + rh, g);
- rn = rh;
- ln = lh;
- addToPendingCount(1);
- m.fork();
- }
-
- int lf = lb + ln, rf = rb + rn; // index bounds
- while (lb < lf && rb < rf) {
- double t, al, ar;
- if ((al = a[lb]) <= (ar = a[rb])) {
- lb++; t = al;
- }
- else {
- rb++; t = ar;
- }
- w[k++] = t;
- }
- if (rb < rf)
- System.arraycopy(a, rb, w, k, rf - rb);
- else if (lb < lf)
- System.arraycopy(a, lb, w, k, lf - lb);
- tryComplete();
- }
- }
- } // FJDouble
-
+ }
}
--- old/src/java.base/share/classes/java/util/DualPivotQuicksort.java 2018-01-18 06:09:10.556930431 -0800
+++ new/src/java.base/share/classes/java/util/DualPivotQuicksort.java 2018-01-18 06:09:10.188896279 -0800
@@ -1,16 +1,16 @@
/*
- * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
+ * published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
@@ -25,23 +25,21 @@
package java.util;
+import java.util.concurrent.ForkJoinTask;
+import java.util.concurrent.RecursiveAction;
+
/**
- * This class implements the Dual-Pivot Quicksort algorithm by
- * Vladimir Yaroslavskiy, Jon Bentley, and Josh Bloch. The algorithm
- * offers O(n log(n)) performance on many data sets that cause other
- * quicksorts to degrade to quadratic performance, and is typically
+ * This class implements powerful and fully optimized versions, both
+ * sequential and parallel, of the Dual-Pivot Quicksort algorithm by
+ * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm
+ * offers O(n log(n)) performance on all data sets, and is typically
* faster than traditional (one-pivot) Quicksort implementations.
*
- * All exposed methods are package-private, designed to be invoked
- * from public methods (in class Arrays) after performing any
- * necessary array bounds checks and expanding parameters into the
- * required forms.
- *
* @author Vladimir Yaroslavskiy
* @author Jon Bentley
* @author Josh Bloch
*
- * @version 2011.02.11 m765.827.12i:5\7pm
+ * @version 2018.02.18
* @since 1.7
*/
final class DualPivotQuicksort {
@@ -51,3131 +49,1858 @@
*/
private DualPivotQuicksort() {}
- /*
- * Tuning parameters.
+ /**
+ * If the length of the leftmost part to be sorted is less than
+ * this constant, heap sort is used in preference to Quicksort.
*/
+ private static final int HEAP_SORT_THRESHOLD = 69;
/**
- * The maximum number of runs in merge sort.
+ * If the length of non-leftmost part to be sorted is less than this
+ * constant, nano insertion sort is used in preference to Quicksort.
*/
- private static final int MAX_RUN_COUNT = 67;
+ private static final int NANO_INSERTION_SORT_THRESHOLD = 36;
/**
- * If the length of an array to be sorted is less than this
- * constant, Quicksort is used in preference to merge sort.
+ * If the length of non-leftmost part to be sorted is less than this
+ * constant, pair insertion sort is used in preference to Quicksort.
*/
- private static final int QUICKSORT_THRESHOLD = 286;
+ private static final int PAIR_INSERTION_SORT_THRESHOLD = 88;
/**
- * If the length of an array to be sorted is less than this
- * constant, insertion sort is used in preference to Quicksort.
+ * The minimal length of an array, required by parallel Quicksort.
*/
- private static final int INSERTION_SORT_THRESHOLD = 47;
+ private static final int PARALLEL_QUICKSORT_THRESHOLD = 1024;
/**
* 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 = 29;
+ private static final int COUNTING_SORT_THRESHOLD_FOR_BYTE = 41;
/**
* 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 = 3200;
+ private static final int COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR = 2180;
- /*
- * Sorting methods for seven primitive types.
+ /**
+ * if the depth of the Quicksort recursion exceeds this
+ * constant, heap sort is used in preference to Quicksort.
*/
+ private static final int MAX_RECURSION_DEPTH = 100;
/**
- * Sorts the specified range of the array using the given
- * workspace array slice if possible for merging
- *
- * @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 work a workspace array (slice)
- * @param workBase origin of usable space in work array
- * @param workLen usable size of work array
- */
- static void sort(int[] a, int left, int right,
- int[] work, int workBase, int workLen) {
- // Use Quicksort on small arrays
- if (right - left < QUICKSORT_THRESHOLD) {
- sort(a, left, right, true);
- return;
- }
-
- /*
- * Index run[i] is the start of i-th run
- * (ascending or descending sequence).
- */
- int[] run = new int[MAX_RUN_COUNT + 1];
- int count = 0; run[0] = left;
-
- // Check if the array is nearly sorted
- for (int k = left; k < right; run[count] = k) {
- // Equal items in the beginning of the sequence
- while (k < right && a[k] == a[k + 1])
- k++;
- if (k == right) break; // Sequence finishes with equal items
- if (a[k] < a[k + 1]) { // ascending
- while (++k <= right && a[k - 1] <= a[k]);
- } else if (a[k] > a[k + 1]) { // descending
- while (++k <= right && a[k - 1] >= a[k]);
- // Transform into an ascending sequence
- for (int lo = run[count] - 1, hi = k; ++lo < --hi; ) {
- int t = a[lo]; a[lo] = a[hi]; a[hi] = t;
- }
- }
+ * This constant is combination of maximum Quicksort recursion depth
+ * and binary flag, where the right bit "0" indicates that the whole
+ * array is considered as the leftmost part.
+ */
+ private static final int LEFTMOST_BITS = MAX_RECURSION_DEPTH << 1;
- // Merge a transformed descending sequence followed by an
- // ascending sequence
- if (run[count] > left && a[run[count]] >= a[run[count] - 1]) {
- count--;
- }
+ /**
+ * This class implements the parallel Dual-Pivot Quicksort.
+ */
+ @SuppressWarnings("serial")
+ private static class Sorter extends RecursiveAction {
- /*
- * The array is not highly structured,
- * use Quicksort instead of merge sort.
- */
- if (++count == MAX_RUN_COUNT) {
- sort(a, left, right, true);
- return;
- }
+ Sorter(T a, int bits, int low, int high) {
+ this.a = a;
+ this.bits = bits;
+ this.low = low;
+ this.high = high;
}
- // These invariants should hold true:
- // run[0] = 0
- // run[] = right + 1; (terminator)
+ @Override
+ protected void compute() {
+ Class> clazz = a.getClass();
- if (count == 0) {
- // A single equal run
- return;
- } else if (count == 1 && run[count] > right) {
- // Either a single ascending or a transformed descending run.
- // Always check that a final run is a proper terminator, otherwise
- // we have an unterminated trailing run, to handle downstream.
- return;
- }
- right++;
- if (run[count] < right) {
- // Corner case: the final run is not a terminator. This may happen
- // if a final run is an equals run, or there is a single-element run
- // at the end. Fix up by adding a proper terminator at the end.
- // Note that we terminate with (right + 1), incremented earlier.
- run[++count] = right;
- }
-
- // Determine alternation base for merge
- byte odd = 0;
- for (int n = 1; (n <<= 1) < count; odd ^= 1);
-
- // Use or create temporary array b for merging
- int[] b; // temp array; alternates with a
- int ao, bo; // array offsets from 'left'
- int blen = right - left; // space needed for b
- if (work == null || workLen < blen || workBase + blen > work.length) {
- work = new int[blen];
- workBase = 0;
- }
- if (odd == 0) {
- System.arraycopy(a, left, work, workBase, blen);
- b = a;
- bo = 0;
- a = work;
- ao = workBase - left;
- } else {
- b = work;
- ao = 0;
- bo = workBase - left;
- }
-
- // Merging
- for (int last; count > 1; count = last) {
- for (int k = (last = 0) + 2; k <= count; k += 2) {
- int hi = run[k], mi = run[k - 1];
- for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) {
- if (q >= hi || p < mi && a[p + ao] <= a[q + ao]) {
- b[i + bo] = a[p++ + ao];
- } else {
- b[i + bo] = a[q++ + ao];
- }
- }
- run[++last] = hi;
- }
- if ((count & 1) != 0) {
- for (int i = right, lo = run[count - 1]; --i >= lo;
- b[i + bo] = a[i + ao]
- );
- run[++last] = right;
+ if (clazz == int[].class) {
+ sort((int[]) a, bits, true, low, high);
+ } else if (clazz == long[].class) {
+ sort((long[]) a, bits, true, low, high);
+ } else if (clazz == char[].class) {
+ sort((char[]) a, bits, true, low, high);
+ } else if (clazz == short[].class) {
+ sort((short[]) a, bits, true, low, high);
+ } else if (clazz == float[].class) {
+ sort((float[]) a, bits, true, low, high);
+ } else if (clazz == double[].class) {
+ sort((double[]) a, bits, true, low, high);
+ } else {
+ throw new IllegalArgumentException(
+ "Unknown type of array: " + clazz.getName());
}
- int[] t = a; a = b; b = t;
- int o = ao; ao = bo; bo = o;
}
+
+ private T a;
+ private int bits;
+ private int low;
+ private int high;
}
/**
- * Sorts the specified range of the array by Dual-Pivot Quicksort.
+ * Sorts the specified range of the array.
*
* @param a the array to be sorted
- * @param left the index of the first element, inclusive, to be sorted
- * @param right the index of the last element, inclusive, to be sorted
- * @param leftmost indicates if 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
- if (length < INSERTION_SORT_THRESHOLD) {
- if (leftmost) {
- /*
- * 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];
- while (ai < a[j]) {
- a[j + 1] = a[j];
- if (j-- == left) {
- break;
- }
- }
- a[j + 1] = ai;
- }
- } else {
- /*
- * Skip the longest ascending sequence.
- */
- do {
- if (left >= right) {
- return;
- }
- } while (a[++left] >= a[left - 1]);
+ * @param parallel indicates whether sorting is performed in parallel
+ * @param low the index of the first element, inclusive, to be sorted
+ * @param high the index of the last element, exclusive, to be sorted
+ */
+ static void sort(int[] a, boolean parallel, int low, int high) {
+ sort(a, LEFTMOST_BITS, parallel, low, high);
+ }
- /*
- * 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 more optimized algorithm, so called pair insertion
- * sort, which is faster (in the context of Quicksort)
- * than traditional implementation of insertion sort.
- */
- for (int k = left; ++left <= right; k = ++left) {
- int a1 = a[k], a2 = a[left];
+ /**
+ * Sorts the specified range of the array by the Dual-Pivot Quicksort.
+ *
+ * @param a the array to be sorted
+ * @param bits the recursion depth of Quicksort and the leftmost flag
+ * @param parallel indicates whether sorting is performed in parallel
+ * @param low the index of the first element, inclusive, to be sorted
+ * @param high the index of the last element, exclusive, to be sorted
+ */
+ private static void sort(int[] a, int bits, boolean parallel, int low, int high) {
+ int end = high - 1, length = high - low;
- if (a1 < a2) {
- a2 = a1; a1 = a[left];
- }
- while (a1 < a[--k]) {
- a[k + 2] = a[k];
- }
- a[++k + 1] = a1;
+ /*
+ * Run insertion sorts on non-leftmost part.
+ */
+ if ((bits & 1) > 0) {
- while (a2 < a[--k]) {
- a[k + 1] = a[k];
- }
- a[k + 1] = a2;
- }
- int last = a[right];
+ /*
+ * Use nano insertion sort on tiny part.
+ */
+ if (length < NANO_INSERTION_SORT_THRESHOLD) {
+ SortingAlgorithms.nanoInsertionSort(a, low, high);
+ return;
+ }
- while (last < a[--right]) {
- a[right + 1] = a[right];
- }
- a[right + 1] = last;
+ /*
+ * Use pair insertion sort on small part.
+ */
+ if (length < PAIR_INSERTION_SORT_THRESHOLD) {
+ SortingAlgorithms.pairInsertionSort(a, low, end);
+ return;
}
+ }
+
+ /*
+ * Switch to heap sort on the leftmost part or
+ * if the execution time is becoming quadratic.
+ */
+ if (length < HEAP_SORT_THRESHOLD || (bits -= 2) < 0) {
+ SortingAlgorithms.heapSort(a, low, end);
return;
}
- // Inexpensive approximation of length / 7
- int seventh = (length >> 3) + (length >> 6) + 1;
+ /*
+ * Check if the array is nearly sorted
+ * and then try to sort it by Merging sort.
+ */
+ if (SortingAlgorithms.mergingSort(a, parallel, low, high)) {
+ return;
+ }
/*
- * 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.
+ * The splitting of the array, defined by the following
+ * step, is related to the inexpensive approximation of
+ * the golden ratio.
*/
- int e3 = (left + right) >>> 1; // The midpoint
- int e2 = e3 - seventh;
- int e1 = e2 - seventh;
- int e4 = e3 + seventh;
- int e5 = e4 + seventh;
+ int step = (length >> 3) * 3 + 3;
- // Sort these elements using insertion sort
- if (a[e2] < a[e1]) { int t = a[e2]; a[e2] = a[e1]; a[e1] = t; }
+ /*
+ * Five elements around (and including) the central element in
+ * the array will be used for pivot selection as described below.
+ * The unequal choice of spacing these elements was empirically
+ * determined to work well on a wide variety of inputs.
+ */
+ int e1 = low + step;
+ int e5 = end - step;
+ int e3 = (e1 + e5) >>> 1;
+ int e2 = (e1 + e3) >>> 1;
+ int e4 = (e3 + e5) >>> 1;
- if (a[e3] < a[e2]) { int 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]) { int 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]) { int 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; }
+ /*
+ * Sort these elements in place by the combination
+ * of 5-element sorting network and insertion sort.
+ */
+ if (a[e5] < a[e3]) { int t = a[e5]; a[e5] = a[e3]; a[e3] = t; }
+ if (a[e4] < a[e2]) { int t = a[e4]; a[e4] = a[e2]; a[e2] = t; }
+ if (a[e5] < a[e4]) { int t = a[e5]; a[e5] = a[e4]; a[e4] = t; }
+ if (a[e3] < a[e2]) { int t = a[e3]; a[e3] = a[e2]; a[e2] = t; }
+ if (a[e4] < a[e3]) { int t = a[e4]; a[e4] = a[e3]; a[e3] = t; }
+
+ if (a[e1] > a[e2]) { int t = a[e1]; a[e1] = a[e2]; a[e2] = t;
+ if (t > a[e3]) { a[e2] = a[e3]; a[e3] = t;
+ if (t > a[e4]) { a[e3] = a[e4]; a[e4] = t;
+ if (t > a[e5]) { a[e4] = a[e5]; a[e5] = t; }
}
}
}
// 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
+ int lower = low; // The index of the last element of the left part
+ int upper = end; // The index of the first element of the right part
+
+ if (a[e1] < a[e2] && a[e2] < a[e3] && a[e3] < a[e4] && a[e4] < a[e5]) {
- if (a[e1] != a[e2] && a[e2] != a[e3] && a[e3] != a[e4] && a[e4] != a[e5]) {
/*
- * Use the second and fourth of the five sorted elements as pivots.
- * These values are inexpensive approximations of the first and
- * second terciles of the array. Note that pivot1 <= pivot2.
+ * Use the first and the fifth elements as the pivots.
+ * These values are inexpensive approximation of tertiles.
+ * Note, that pivot1 < pivot2.
*/
- int pivot1 = a[e2];
- int pivot2 = a[e4];
+ int pivot1 = a[e1];
+ int pivot2 = a[e5];
/*
* 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
+ * is completed, the pivots are swapped back into their final
* positions, and excluded from subsequent sorting.
*/
- a[e2] = a[left];
- a[e4] = a[right];
+ a[e1] = a[lower];
+ a[e5] = a[upper];
/*
- * Skip elements, which are less or greater than pivot values.
+ * Skip elements, which are less or greater than the pivots.
*/
- while (a[++less] < pivot1);
- while (a[--great] > pivot2);
+ while (a[++lower] < pivot1);
+ while (a[--upper] > pivot2);
/*
- * Partitioning:
+ * Backwards 3-interval partitioning
*
- * left part center part right part
- * +--------------------------------------------------------------+
- * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 |
- * +--------------------------------------------------------------+
- * ^ ^ ^
- * | | |
- * less k great
+ * left part central part right part
+ * +------------------------------------------------------------+
+ * | < pivot1 | ? | pivot1 <= && <= pivot2 | > pivot2 |
+ * +------------------------------------------------------------+
+ * ^ ^ ^
+ * | | |
+ * lower k upper
*
* Invariants:
*
- * all in (left, less) < pivot1
- * pivot1 <= all in [less, k) <= pivot2
- * all in (great, right) > pivot2
+ * all in (low, lower] < pivot1
+ * pivot1 <= all in (k, upper) <= pivot2
+ * all in [upper, end) > pivot2
*
- * Pointer k is the first index of ?-part.
+ * Pointer k is the last index of ?-part
*/
- outer:
- for (int k = less - 1; ++k <= great; ) {
+ for (int $ = --lower, k = ++upper; --k > lower; ) {
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
- while (a[great] > pivot2) {
- if (great-- == k) {
- break outer;
- }
- }
- 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;
- }
- }
-
- // 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 > 4/7 of the array),
- * swap internal pivot values to ends.
- */
- if (less < e1 && e5 < great) {
- /*
- * Skip elements, which are equal to pivot values.
- */
- while (a[less] == pivot1) {
- ++less;
- }
-
- while (a[great] == pivot2) {
- --great;
- }
-
- /*
- * Partitioning:
- *
- * left part center part right part
- * +----------------------------------------------------------+
- * | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 |
- * +----------------------------------------------------------+
- * ^ ^ ^
- * | | |
- * less k great
- *
- * Invariants:
- *
- * all in (*, less) == pivot1
- * pivot1 < all in [less, k) < pivot2
- * all in (great, *) == pivot2
- *
- * Pointer k is the first index of ?-part.
- */
- outer:
- for (int k = less - 1; ++k <= great; ) {
- int 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[great] < pivot2
- 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;
+
+ if (ak < pivot1) { // Move a[k] to the left side
+ while (a[++lower] < pivot1);
+
+ if (lower > k) {
+ lower = k;
+ break;
+ }
+ if (a[lower] > pivot2) { // a[lower] >= pivot1
+ a[k] = a[--upper];
+ a[upper] = a[lower];
+ } else { // pivot1 <= a[lower] <= pivot2
+ a[k] = a[lower];
}
+ a[lower] = ak;
+ } else if (ak > pivot2) { // Move a[k] to the right side
+ a[k] = a[--upper];
+ a[upper] = ak;
}
}
- // Sort center part recursively
- sort(a, less, great, false);
+ /*
+ * Swap the pivots into their final positions.
+ */
+ a[low] = a[lower]; a[lower] = pivot1;
+ a[end] = a[upper]; a[upper] = pivot2;
+ /*
+ * Sort all parts recursively, excluding known pivots.
+ */
+ if (parallel && length > PARALLEL_QUICKSORT_THRESHOLD) {
+ ForkJoinTask.invokeAll(
+ new Sorter(a, bits | 1, lower + 1, upper),
+ new Sorter(a, bits | 1, upper + 1, high),
+ new Sorter(a, bits, low, lower)
+ );
+ } else {
+ sort(a, bits | 1, false, upper + 1, high);
+ sort(a, bits, false, low, lower);
+ sort(a, bits | 1, false, lower + 1, upper);
+ }
} else { // Partitioning with one pivot
+
/*
- * Use the third of the five sorted elements as pivot.
- * This value is inexpensive approximation of the median.
+ * Use the third element as the pivot. This value
+ * is inexpensive approximation of the median.
*/
int pivot = a[e3];
/*
- * Partitioning degenerates to the traditional 3-way
- * (or "Dutch National Flag") schema:
- *
- * left part center part right part
- * +-------------------------------------------------+
- * | < pivot | == pivot | ? | > pivot |
- * +-------------------------------------------------+
- * ^ ^ ^
- * | | |
- * less k great
+ * The first element to be sorted is moved to the location
+ * formerly occupied by the pivot. When partitioning is
+ * completed, the pivot is swapped back into its final
+ * position, and excluded from subsequent sorting.
+ */
+ a[e3] = a[lower];
+
+ /*
+ * Traditional 3-way (Dutch National Flag) partitioning
+ *
+ * left part central part right part
+ * +------------------------------------------------------+
+ * | < pivot | ? | == pivot | > pivot |
+ * +------------------------------------------------------+
+ * ^ ^ ^
+ * | | |
+ * lower k upper
*
* Invariants:
*
- * all in (left, less) < pivot
- * all in [less, k) == pivot
- * all in (great, right) > pivot
+ * all in (low, lower] < pivot
+ * all in (k, upper) == pivot
+ * all in [upper, end] > pivot
*
- * Pointer k is the first index of ?-part.
+ * Pointer k is the last index of ?-part
*/
- for (int k = less; k <= great; ++k) {
+ for (int k = ++upper; --k > lower; ) {
if (a[k] == pivot) {
continue;
}
int ak = a[k];
- if (ak < pivot) { // Move a[k] to left part
- a[k] = a[less];
- a[less] = ak;
- ++less;
- } else { // a[k] > pivot - Move a[k] to right part
- while (a[great] > pivot) {
- --great;
- }
- if (a[great] < pivot) { // a[great] <= pivot
- a[k] = a[less];
- a[less] = a[great];
- ++less;
- } else { // a[great] == pivot
- /*
- * Even though a[great] equals to pivot, the
- * assignment a[k] = pivot may be incorrect,
- * if a[great] and pivot 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] = pivot;
+
+ if (ak < pivot) { // Move a[k] to the left side
+ while (a[++lower] < pivot);
+
+ if (lower > k) {
+ lower = k;
+ break;
+ }
+ a[k] = pivot;
+
+ if (a[lower] > pivot) {
+ a[--upper] = a[lower];
}
- a[great] = ak;
- --great;
+ a[lower] = ak;
+ } else { // ak > pivot - Move a[k] to the right side
+ a[k] = pivot;
+ a[--upper] = ak;
}
}
/*
- * Sort left and right parts recursively.
- * All elements from center part are equal
+ * Swap the pivot into its final position.
+ */
+ a[low] = a[lower]; a[lower] = pivot;
+
+ /*
+ * Sort the left and the right parts recursively, excluding
+ * known pivot. All elements from the central part are equal
* and, therefore, already sorted.
*/
- sort(a, left, less - 1, leftmost);
- sort(a, great + 1, right, false);
+ if (parallel && length > PARALLEL_QUICKSORT_THRESHOLD) {
+ ForkJoinTask.invokeAll(
+ new Sorter(a, bits, low, lower),
+ new Sorter(a, bits | 1, upper, high)
+ );
+ } else {
+ sort(a, bits | 1, false, upper, high);
+ sort(a, bits, false, low, lower);
+ }
}
}
/**
- * Sorts the specified range of the array using the given
- * workspace array slice if possible for merging
+ * Sorts the specified range of the array.
*
* @param a the array to be sorted
- * @param left the index of the first element, inclusive, to be sorted
- * @param right the index of the last element, inclusive, to be sorted
- * @param work a workspace array (slice)
- * @param workBase origin of usable space in work array
- * @param workLen usable size of work array
- */
- static void sort(long[] a, int left, int right,
- long[] work, int workBase, int workLen) {
- // Use Quicksort on small arrays
- if (right - left < QUICKSORT_THRESHOLD) {
- sort(a, left, right, true);
- return;
- }
+ * @param parallel indicates whether sorting is performed in parallel
+ * @param low the index of the first element, inclusive, to be sorted
+ * @param high the index of the last element, exclusive, to be sorted
+ */
+ static void sort(long[] a, boolean parallel, int low, int high) {
+ sort(a, LEFTMOST_BITS, parallel, low, high);
+ }
+
+ /**
+ * Sorts the specified range of the array by the Dual-Pivot Quicksort.
+ *
+ * @param a the array to be sorted
+ * @param bits the recursion depth of Quicksort and the leftmost flag
+ * @param parallel indicates whether sorting is performed in parallel
+ * @param low the index of the first element, inclusive, to be sorted
+ * @param high the index of the last element, exclusive, to be sorted
+ */
+ private static void sort(long[] a, int bits, boolean parallel, int low, int high) {
+ int end = high - 1, length = high - low;
/*
- * Index run[i] is the start of i-th run
- * (ascending or descending sequence).
+ * Run insertion sorts on non-leftmost part.
*/
- int[] run = new int[MAX_RUN_COUNT + 1];
- int count = 0; run[0] = left;
+ if ((bits & 1) > 0) {
- // Check if the array is nearly sorted
- for (int k = left; k < right; run[count] = k) {
- // Equal items in the beginning of the sequence
- while (k < right && a[k] == a[k + 1])
- k++;
- if (k == right) break; // Sequence finishes with equal items
- if (a[k] < a[k + 1]) { // ascending
- while (++k <= right && a[k - 1] <= a[k]);
- } else if (a[k] > a[k + 1]) { // descending
- while (++k <= right && a[k - 1] >= a[k]);
- // Transform into an ascending sequence
- for (int lo = run[count] - 1, hi = k; ++lo < --hi; ) {
- long t = a[lo]; a[lo] = a[hi]; a[hi] = t;
- }
- }
-
- // Merge a transformed descending sequence followed by an
- // ascending sequence
- if (run[count] > left && a[run[count]] >= a[run[count] - 1]) {
- count--;
+ /*
+ * Use nano insertion sort on tiny part.
+ */
+ if (length < NANO_INSERTION_SORT_THRESHOLD) {
+ SortingAlgorithms.nanoInsertionSort(a, low, high);
+ return;
}
/*
- * The array is not highly structured,
- * use Quicksort instead of merge sort.
+ * Use pair insertion sort on small part.
*/
- if (++count == MAX_RUN_COUNT) {
- sort(a, left, right, true);
+ if (length < PAIR_INSERTION_SORT_THRESHOLD) {
+ SortingAlgorithms.pairInsertionSort(a, low, end);
return;
}
}
- // These invariants should hold true:
- // run[0] = 0
- // run[] = right + 1; (terminator)
-
- if (count == 0) {
- // A single equal run
- return;
- } else if (count == 1 && run[count] > right) {
- // Either a single ascending or a transformed descending run.
- // Always check that a final run is a proper terminator, otherwise
- // we have an unterminated trailing run, to handle downstream.
+ /*
+ * Switch to heap sort on the leftmost part or
+ * if the execution time is becoming quadratic.
+ */
+ if (length < HEAP_SORT_THRESHOLD || (bits -= 2) < 0) {
+ SortingAlgorithms.heapSort(a, low, end);
return;
}
- right++;
- if (run[count] < right) {
- // Corner case: the final run is not a terminator. This may happen
- // if a final run is an equals run, or there is a single-element run
- // at the end. Fix up by adding a proper terminator at the end.
- // Note that we terminate with (right + 1), incremented earlier.
- run[++count] = right;
- }
-
- // Determine alternation base for merge
- byte odd = 0;
- for (int n = 1; (n <<= 1) < count; odd ^= 1);
-
- // Use or create temporary array b for merging
- long[] b; // temp array; alternates with a
- int ao, bo; // array offsets from 'left'
- int blen = right - left; // space needed for b
- if (work == null || workLen < blen || workBase + blen > work.length) {
- work = new long[blen];
- workBase = 0;
- }
- if (odd == 0) {
- System.arraycopy(a, left, work, workBase, blen);
- b = a;
- bo = 0;
- a = work;
- ao = workBase - left;
- } else {
- b = work;
- ao = 0;
- bo = workBase - left;
- }
-
- // Merging
- for (int last; count > 1; count = last) {
- for (int k = (last = 0) + 2; k <= count; k += 2) {
- int hi = run[k], mi = run[k - 1];
- for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) {
- if (q >= hi || p < mi && a[p + ao] <= a[q + ao]) {
- b[i + bo] = a[p++ + ao];
- } else {
- b[i + bo] = a[q++ + ao];
- }
- }
- run[++last] = hi;
- }
- if ((count & 1) != 0) {
- for (int i = right, lo = run[count - 1]; --i >= lo;
- b[i + bo] = a[i + ao]
- );
- run[++last] = right;
- }
- long[] t = a; a = b; b = t;
- int o = ao; ao = bo; bo = o;
- }
- }
-
- /**
- * Sorts the specified range of the array by Dual-Pivot Quicksort.
- *
- * @param a the array to be sorted
- * @param left the index of the first element, inclusive, to be sorted
- * @param right the index of the last element, inclusive, to be sorted
- * @param leftmost indicates if this part is the leftmost in the range
- */
- private static void sort(long[] a, int left, int right, boolean leftmost) {
- int length = right - left + 1;
-
- // Use insertion sort on tiny arrays
- if (length < INSERTION_SORT_THRESHOLD) {
- if (leftmost) {
- /*
- * 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];
- while (ai < a[j]) {
- a[j + 1] = a[j];
- if (j-- == left) {
- break;
- }
- }
- a[j + 1] = ai;
- }
- } else {
- /*
- * Skip the longest ascending sequence.
- */
- do {
- if (left >= right) {
- return;
- }
- } while (a[++left] >= a[left - 1]);
-
- /*
- * 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 more optimized algorithm, so called pair insertion
- * sort, which is faster (in the context of Quicksort)
- * than traditional implementation of insertion sort.
- */
- for (int k = left; ++left <= right; k = ++left) {
- long a1 = a[k], a2 = a[left];
- if (a1 < a2) {
- a2 = a1; a1 = a[left];
- }
- while (a1 < a[--k]) {
- a[k + 2] = a[k];
- }
- a[++k + 1] = a1;
-
- while (a2 < a[--k]) {
- a[k + 1] = a[k];
- }
- a[k + 1] = a2;
- }
- long last = a[right];
-
- while (last < a[--right]) {
- a[right + 1] = a[right];
- }
- a[right + 1] = last;
- }
+ /*
+ * Check if the array is nearly sorted
+ * and then try to sort it by Merging sort.
+ */
+ if (SortingAlgorithms.mergingSort(a, parallel, low, high)) {
return;
}
- // Inexpensive approximation of length / 7
- int seventh = (length >> 3) + (length >> 6) + 1;
+ /*
+ * The splitting of the array, defined by the following
+ * step, is related to the inexpensive approximation of
+ * the golden ratio.
+ */
+ int step = (length >> 3) * 3 + 3;
/*
- * 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.
+ * Five elements around (and including) the central element in
+ * the array will be used for pivot selection as described below.
+ * The unequal choice of 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;
+ int e1 = low + step;
+ int e5 = end - step;
+ int e3 = (e1 + e5) >>> 1;
+ int e2 = (e1 + e3) >>> 1;
+ int e4 = (e3 + e5) >>> 1;
- // Sort these elements using insertion sort
- if (a[e2] < a[e1]) { long t = a[e2]; a[e2] = a[e1]; a[e1] = t; }
+ /*
+ * Sort these elements in place by the combination
+ * of 5-element sorting network and insertion sort.
+ */
+ if (a[e5] < a[e3]) { long t = a[e5]; a[e5] = a[e3]; a[e3] = t; }
+ if (a[e4] < a[e2]) { long t = a[e4]; a[e4] = a[e2]; a[e2] = t; }
+ if (a[e5] < a[e4]) { long t = a[e5]; a[e5] = a[e4]; a[e4] = t; }
+ if (a[e3] < a[e2]) { long t = a[e3]; a[e3] = a[e2]; a[e2] = t; }
+ if (a[e4] < a[e3]) { long t = a[e4]; a[e4] = a[e3]; a[e3] = 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; }
+ if (a[e1] > a[e2]) { long t = a[e1]; a[e1] = a[e2]; a[e2] = t;
+ if (t > a[e3]) { a[e2] = a[e3]; a[e3] = t;
+ if (t > a[e4]) { a[e3] = a[e4]; a[e4] = t;
+ if (t > a[e5]) { a[e4] = a[e5]; a[e5] = t; }
}
}
}
// 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
+ int lower = low; // The index of the last element of the left part
+ int upper = end; // The index of the first element of the right part
+
+ if (a[e1] < a[e2] && a[e2] < a[e3] && a[e3] < a[e4] && a[e4] < a[e5]) {
- if (a[e1] != a[e2] && a[e2] != a[e3] && a[e3] != a[e4] && a[e4] != a[e5]) {
/*
- * Use the second and fourth of the five sorted elements as pivots.
- * These values are inexpensive approximations of the first and
- * second terciles of the array. Note that pivot1 <= pivot2.
+ * Use the first and the fifth elements as the pivots.
+ * These values are inexpensive approximation of tertiles.
+ * Note, that pivot1 < pivot2.
*/
- long pivot1 = a[e2];
- long pivot2 = a[e4];
+ long pivot1 = a[e1];
+ long pivot2 = a[e5];
/*
* 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
+ * is completed, the pivots are swapped back into their final
* positions, and excluded from subsequent sorting.
*/
- a[e2] = a[left];
- a[e4] = a[right];
+ a[e1] = a[lower];
+ a[e5] = a[upper];
/*
- * Skip elements, which are less or greater than pivot values.
+ * Skip elements, which are less or greater than the pivots.
*/
- while (a[++less] < pivot1);
- while (a[--great] > pivot2);
+ while (a[++lower] < pivot1);
+ while (a[--upper] > pivot2);
/*
- * Partitioning:
+ * Backwards 3-interval partitioning
*
- * left part center part right part
- * +--------------------------------------------------------------+
- * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 |
- * +--------------------------------------------------------------+
- * ^ ^ ^
- * | | |
- * less k great
+ * left part central part right part
+ * +------------------------------------------------------------+
+ * | < pivot1 | ? | pivot1 <= && <= pivot2 | > pivot2 |
+ * +------------------------------------------------------------+
+ * ^ ^ ^
+ * | | |
+ * lower k upper
*
* Invariants:
*
- * all in (left, less) < pivot1
- * pivot1 <= all in [less, k) <= pivot2
- * all in (great, right) > pivot2
+ * all in (low, lower] < pivot1
+ * pivot1 <= all in (k, upper) <= pivot2
+ * all in [upper, end) > pivot2
*
- * Pointer k is the first index of ?-part.
+ * Pointer k is the last index of ?-part
*/
- outer:
- for (int k = less - 1; ++k <= great; ) {
+ for (int $ = --lower, k = ++upper; --k > lower; ) {
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
- while (a[great] > pivot2) {
- if (great-- == k) {
- break outer;
- }
- }
- 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;
- }
- }
-
- // 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 > 4/7 of the array),
- * swap internal pivot values to ends.
- */
- if (less < e1 && e5 < great) {
- /*
- * Skip elements, which are equal to pivot values.
- */
- while (a[less] == pivot1) {
- ++less;
- }
-
- while (a[great] == pivot2) {
- --great;
- }
-
- /*
- * Partitioning:
- *
- * left part center part right part
- * +----------------------------------------------------------+
- * | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 |
- * +----------------------------------------------------------+
- * ^ ^ ^
- * | | |
- * less k great
- *
- * Invariants:
- *
- * all in (*, less) == pivot1
- * pivot1 < all in [less, k) < pivot2
- * all in (great, *) == pivot2
- *
- * Pointer k is the first index of ?-part.
- */
- outer:
- for (int k = less - 1; ++k <= great; ) {
- 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[great] < pivot2
- 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;
+
+ if (ak < pivot1) { // Move a[k] to the left side
+ while (a[++lower] < pivot1);
+
+ if (lower > k) {
+ lower = k;
+ break;
}
+ if (a[lower] > pivot2) { // a[lower] >= pivot1
+ a[k] = a[--upper];
+ a[upper] = a[lower];
+ } else { // pivot1 <= a[lower] <= pivot2
+ a[k] = a[lower];
+ }
+ a[lower] = ak;
+ } else if (ak > pivot2) { // Move a[k] to the right side
+ a[k] = a[--upper];
+ a[upper] = ak;
}
}
- // Sort center part recursively
- sort(a, less, great, false);
+ /*
+ * Swap the pivots into their final positions.
+ */
+ a[low] = a[lower]; a[lower] = pivot1;
+ a[end] = a[upper]; a[upper] = pivot2;
+ /*
+ * Sort all parts recursively, excluding known pivots.
+ */
+ if (parallel && length > PARALLEL_QUICKSORT_THRESHOLD) {
+ ForkJoinTask.invokeAll(
+ new Sorter(a, bits | 1, lower + 1, upper),
+ new Sorter(a, bits | 1, upper + 1, high),
+ new Sorter(a, bits, low, lower)
+ );
+ } else {
+ sort(a, bits | 1, false, upper + 1, high);
+ sort(a, bits, false, low, lower);
+ sort(a, bits | 1, false, lower + 1, upper);
+ }
} else { // Partitioning with one pivot
+
/*
- * Use the third of the five sorted elements as pivot.
- * This value is inexpensive approximation of the median.
+ * Use the third element as the pivot. This value
+ * is inexpensive approximation of the median.
*/
long pivot = a[e3];
/*
- * Partitioning degenerates to the traditional 3-way
- * (or "Dutch National Flag") schema:
- *
- * left part center part right part
- * +-------------------------------------------------+
- * | < pivot | == pivot | ? | > pivot |
- * +-------------------------------------------------+
- * ^ ^ ^
- * | | |
- * less k great
+ * The first element to be sorted is moved to the location
+ * formerly occupied by the pivot. When partitioning is
+ * completed, the pivot is swapped back into its final
+ * position, and excluded from subsequent sorting.
+ */
+ a[e3] = a[lower];
+
+ /*
+ * Traditional 3-way (Dutch National Flag) partitioning
+ *
+ * left part central part right part
+ * +------------------------------------------------------+
+ * | < pivot | ? | == pivot | > pivot |
+ * +------------------------------------------------------+
+ * ^ ^ ^
+ * | | |
+ * lower k upper
*
* Invariants:
*
- * all in (left, less) < pivot
- * all in [less, k) == pivot
- * all in (great, right) > pivot
+ * all in (low, lower] < pivot
+ * all in (k, upper) == pivot
+ * all in [upper, end] > pivot
*
- * Pointer k is the first index of ?-part.
+ * Pointer k is the last index of ?-part
*/
- for (int k = less; k <= great; ++k) {
+ for (int k = ++upper; --k > lower; ) {
if (a[k] == pivot) {
continue;
}
long ak = a[k];
- if (ak < pivot) { // Move a[k] to left part
- a[k] = a[less];
- a[less] = ak;
- ++less;
- } else { // a[k] > pivot - Move a[k] to right part
- while (a[great] > pivot) {
- --great;
- }
- if (a[great] < pivot) { // a[great] <= pivot
- a[k] = a[less];
- a[less] = a[great];
- ++less;
- } else { // a[great] == pivot
- /*
- * Even though a[great] equals to pivot, the
- * assignment a[k] = pivot may be incorrect,
- * if a[great] and pivot 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] = pivot;
+
+ if (ak < pivot) { // Move a[k] to the left side
+ while (a[++lower] < pivot);
+
+ if (lower > k) {
+ lower = k;
+ break;
+ }
+ a[k] = pivot;
+
+ if (a[lower] > pivot) {
+ a[--upper] = a[lower];
}
- a[great] = ak;
- --great;
+ a[lower] = ak;
+ } else { // ak > pivot - Move a[k] to the right side
+ a[k] = pivot;
+ a[--upper] = ak;
}
}
/*
- * Sort left and right parts recursively.
- * All elements from center part are equal
+ * Swap the pivot into its final position.
+ */
+ a[low] = a[lower]; a[lower] = pivot;
+
+ /*
+ * Sort the left and the right parts recursively, excluding
+ * known pivot. All elements from the central part are equal
* and, therefore, already sorted.
*/
- sort(a, left, less - 1, leftmost);
- sort(a, great + 1, right, false);
+ if (parallel && length > PARALLEL_QUICKSORT_THRESHOLD) {
+ ForkJoinTask.invokeAll(
+ new Sorter(a, bits, low, lower),
+ new Sorter(a, bits | 1, upper, high)
+ );
+ } else {
+ sort(a, bits | 1, false, upper, high);
+ sort(a, bits, false, low, lower);
+ }
}
}
/**
- * Sorts the specified range of the array using the given
- * workspace array slice if possible for merging
+ * Sorts the specified range of the array.
*
* @param a the array to be sorted
- * @param left the index of the first element, inclusive, to be sorted
- * @param right the index of the last element, inclusive, to be sorted
- * @param work a workspace array (slice)
- * @param workBase origin of usable space in work array
- * @param workLen usable size of work array
- */
- static void sort(short[] a, int left, int right,
- short[] work, int workBase, int workLen) {
- // 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 - 1; ++i <= right;
- count[a[i] - Short.MIN_VALUE]++
- );
- for (int i = NUM_SHORT_VALUES, k = right + 1; k > left; ) {
- while (count[--i] == 0);
- short value = (short) (i + Short.MIN_VALUE);
- int s = count[i];
-
- do {
- a[--k] = value;
- } while (--s > 0);
- }
- } else { // Use Dual-Pivot Quicksort on small arrays
- doSort(a, left, right, work, workBase, workLen);
+ * @param parallel indicates whether sorting is performed in parallel
+ * @param low the index of the first element, inclusive, to be sorted
+ * @param high the index of the last element, exclusive, to be sorted
+ */
+ static void sort(byte[] a, boolean parallel, int low, int high) {
+ if (high - low > COUNTING_SORT_THRESHOLD_FOR_BYTE) {
+ SortingAlgorithms.countingSort(a, low, high);
+ } else {
+ SortingAlgorithms.insertionSort(a, low, high);
}
}
- /** The number of distinct short values. */
- private static final int NUM_SHORT_VALUES = 1 << 16;
-
/**
* Sorts the specified range of the array.
*
* @param a the array to be sorted
- * @param left the index of the first element, inclusive, to be sorted
- * @param right the index of the last element, inclusive, to be sorted
- * @param work a workspace array (slice)
- * @param workBase origin of usable space in work array
- * @param workLen usable size of work array
- */
- private static void doSort(short[] a, int left, int right,
- short[] work, int workBase, int workLen) {
- // Use Quicksort on small arrays
- if (right - left < QUICKSORT_THRESHOLD) {
- sort(a, left, right, true);
- return;
+ * @param parallel indicates whether sorting is performed in parallel
+ * @param low the index of the first element, inclusive, to be sorted
+ * @param high the index of the last element, exclusive, to be sorted
+ */
+ static void sort(char[] a, boolean parallel, int low, int high) {
+ if (high - low > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) {
+ SortingAlgorithms.countingSort(a, low, high);
+ } else {
+ sort(a, LEFTMOST_BITS, parallel, low, high);
}
+ }
+
+ /**
+ * Sorts the specified range of the array by the Dual-Pivot Quicksort.
+ *
+ * @param a the array to be sorted
+ * @param bits the recursion depth of Quicksort and the leftmost flag
+ * @param parallel indicates whether sorting is performed in parallel
+ * @param low the index of the first element, inclusive, to be sorted
+ * @param high the index of the last element, exclusive, to be sorted
+ */
+ private static void sort(char[] a, int bits, boolean parallel, int low, int high) {
+ int end = high - 1, length = high - low;
/*
- * Index run[i] is the start of i-th run
- * (ascending or descending sequence).
+ * Run insertion sorts on non-leftmost part.
*/
- int[] run = new int[MAX_RUN_COUNT + 1];
- int count = 0; run[0] = left;
-
- // Check if the array is nearly sorted
- for (int k = left; k < right; run[count] = k) {
- // Equal items in the beginning of the sequence
- while (k < right && a[k] == a[k + 1])
- k++;
- if (k == right) break; // Sequence finishes with equal items
- if (a[k] < a[k + 1]) { // ascending
- while (++k <= right && a[k - 1] <= a[k]);
- } else if (a[k] > a[k + 1]) { // descending
- while (++k <= right && a[k - 1] >= a[k]);
- // Transform into an ascending sequence
- for (int lo = run[count] - 1, hi = k; ++lo < --hi; ) {
- short t = a[lo]; a[lo] = a[hi]; a[hi] = t;
- }
- }
+ if ((bits & 1) > 0) {
- // Merge a transformed descending sequence followed by an
- // ascending sequence
- if (run[count] > left && a[run[count]] >= a[run[count] - 1]) {
- count--;
+ /*
+ * Use nano insertion sort on tiny part.
+ */
+ if (length < NANO_INSERTION_SORT_THRESHOLD) {
+ SortingAlgorithms.nanoInsertionSort(a, low, high);
+ return;
}
/*
- * The array is not highly structured,
- * use Quicksort instead of merge sort.
+ * Use pair insertion sort on small part.
*/
- if (++count == MAX_RUN_COUNT) {
- sort(a, left, right, true);
+ if (length < PAIR_INSERTION_SORT_THRESHOLD) {
+ SortingAlgorithms.pairInsertionSort(a, low, end);
return;
}
}
- // These invariants should hold true:
- // run[0] = 0
- // run[] = right + 1; (terminator)
-
- if (count == 0) {
- // A single equal run
- return;
- } else if (count == 1 && run[count] > right) {
- // Either a single ascending or a transformed descending run.
- // Always check that a final run is a proper terminator, otherwise
- // we have an unterminated trailing run, to handle downstream.
+ /*
+ * Switch to heap sort on the leftmost part or
+ * if the execution time is becoming quadratic.
+ */
+ if (length < HEAP_SORT_THRESHOLD || (bits -= 2) < 0) {
+ SortingAlgorithms.heapSort(a, low, end);
return;
}
- right++;
- if (run[count] < right) {
- // Corner case: the final run is not a terminator. This may happen
- // if a final run is an equals run, or there is a single-element run
- // at the end. Fix up by adding a proper terminator at the end.
- // Note that we terminate with (right + 1), incremented earlier.
- run[++count] = right;
- }
-
- // Determine alternation base for merge
- byte odd = 0;
- for (int n = 1; (n <<= 1) < count; odd ^= 1);
-
- // Use or create temporary array b for merging
- short[] b; // temp array; alternates with a
- int ao, bo; // array offsets from 'left'
- int blen = right - left; // space needed for b
- if (work == null || workLen < blen || workBase + blen > work.length) {
- work = new short[blen];
- workBase = 0;
- }
- if (odd == 0) {
- System.arraycopy(a, left, work, workBase, blen);
- b = a;
- bo = 0;
- a = work;
- ao = workBase - left;
- } else {
- b = work;
- ao = 0;
- bo = workBase - left;
- }
-
- // Merging
- for (int last; count > 1; count = last) {
- for (int k = (last = 0) + 2; k <= count; k += 2) {
- int hi = run[k], mi = run[k - 1];
- for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) {
- if (q >= hi || p < mi && a[p + ao] <= a[q + ao]) {
- b[i + bo] = a[p++ + ao];
- } else {
- b[i + bo] = a[q++ + ao];
- }
- }
- run[++last] = hi;
- }
- if ((count & 1) != 0) {
- for (int i = right, lo = run[count - 1]; --i >= lo;
- b[i + bo] = a[i + ao]
- );
- run[++last] = right;
- }
- short[] t = a; a = b; b = t;
- int o = ao; ao = bo; bo = o;
- }
- }
-
- /**
- * Sorts the specified range of the array by Dual-Pivot Quicksort.
- *
- * @param a the array to be sorted
- * @param left the index of the first element, inclusive, to be sorted
- * @param right the index of the last element, inclusive, to be sorted
- * @param leftmost indicates if this part is the leftmost in the range
- */
- private static void sort(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) {
- /*
- * Traditional (without sentinel) insertion sort,
- * optimized for server VM, is used in case of
- * the leftmost part.
- */
- for (int i = left, j = i; i < right; j = ++i) {
- short ai = a[i + 1];
- while (ai < a[j]) {
- a[j + 1] = a[j];
- if (j-- == left) {
- break;
- }
- }
- a[j + 1] = ai;
- }
- } else {
- /*
- * Skip the longest ascending sequence.
- */
- do {
- if (left >= right) {
- return;
- }
- } while (a[++left] >= a[left - 1]);
-
- /*
- * 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 more optimized algorithm, so called pair insertion
- * sort, which is faster (in the context of Quicksort)
- * than traditional implementation of insertion sort.
- */
- for (int k = left; ++left <= right; k = ++left) {
- short a1 = a[k], a2 = a[left];
-
- if (a1 < a2) {
- a2 = a1; a1 = 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;
- }
+ /*
+ * Check if the array is nearly sorted
+ * and then try to sort it by Merging sort.
+ */
+ if (SortingAlgorithms.mergingSort(a, parallel, low, high)) {
return;
}
- // Inexpensive approximation of length / 7
- int seventh = (length >> 3) + (length >> 6) + 1;
+ /*
+ * The splitting of the array, defined by the following
+ * step, is related to the inexpensive approximation of
+ * the golden ratio.
+ */
+ int step = (length >> 3) * 3 + 3;
/*
- * 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.
+ * Five elements around (and including) the central element in
+ * the array will be used for pivot selection as described below.
+ * The unequal choice of 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;
+ int e1 = low + step;
+ int e5 = end - step;
+ int e3 = (e1 + e5) >>> 1;
+ int e2 = (e1 + e3) >>> 1;
+ int e4 = (e3 + e5) >>> 1;
- // Sort these elements using insertion sort
- if (a[e2] < a[e1]) { short t = a[e2]; a[e2] = a[e1]; a[e1] = t; }
+ /*
+ * Sort these elements in place by the combination
+ * of 5-element sorting network and insertion sort.
+ */
+ if (a[e5] < a[e3]) { char t = a[e5]; a[e5] = a[e3]; a[e3] = t; }
+ if (a[e4] < a[e2]) { char t = a[e4]; a[e4] = a[e2]; a[e2] = t; }
+ if (a[e5] < a[e4]) { char t = a[e5]; a[e5] = a[e4]; a[e4] = t; }
+ if (a[e3] < a[e2]) { char t = a[e3]; a[e3] = a[e2]; a[e2] = t; }
+ if (a[e4] < a[e3]) { char t = a[e4]; a[e4] = a[e3]; a[e3] = 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]) { 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]) { 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; }
+ if (a[e1] > a[e2]) { char t = a[e1]; a[e1] = a[e2]; a[e2] = t;
+ if (t > a[e3]) { a[e2] = a[e3]; a[e3] = t;
+ if (t > a[e4]) { a[e3] = a[e4]; a[e4] = t;
+ if (t > a[e5]) { a[e4] = a[e5]; a[e5] = t; }
}
}
}
// 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
+ int lower = low; // The index of the last element of the left part
+ int upper = end; // The index of the first element of the right part
+
+ if (a[e1] < a[e2] && a[e2] < a[e3] && a[e3] < a[e4] && a[e4] < a[e5]) {
- if (a[e1] != a[e2] && a[e2] != a[e3] && a[e3] != a[e4] && a[e4] != a[e5]) {
/*
- * Use the second and fourth of the five sorted elements as pivots.
- * These values are inexpensive approximations of the first and
- * second terciles of the array. Note that pivot1 <= pivot2.
+ * Use the first and the fifth elements as the pivots.
+ * These values are inexpensive approximation of tertiles.
+ * Note, that pivot1 < pivot2.
*/
- short pivot1 = a[e2];
- short pivot2 = a[e4];
+ char pivot1 = a[e1];
+ char pivot2 = a[e5];
/*
* 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
+ * is completed, the pivots are swapped back into their final
* positions, and excluded from subsequent sorting.
*/
- a[e2] = a[left];
- a[e4] = a[right];
+ a[e1] = a[lower];
+ a[e5] = a[upper];
/*
- * Skip elements, which are less or greater than pivot values.
+ * Skip elements, which are less or greater than the pivots.
*/
- while (a[++less] < pivot1);
- while (a[--great] > pivot2);
+ while (a[++lower] < pivot1);
+ while (a[--upper] > pivot2);
/*
- * Partitioning:
+ * Backwards 3-interval partitioning
*
- * left part center part right part
- * +--------------------------------------------------------------+
- * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 |
- * +--------------------------------------------------------------+
- * ^ ^ ^
- * | | |
- * less k great
+ * left part central part right part
+ * +------------------------------------------------------------+
+ * | < pivot1 | ? | pivot1 <= && <= pivot2 | > pivot2 |
+ * +------------------------------------------------------------+
+ * ^ ^ ^
+ * | | |
+ * lower k upper
*
* Invariants:
*
- * all in (left, less) < pivot1
- * pivot1 <= all in [less, k) <= pivot2
- * all in (great, right) > pivot2
+ * all in (low, lower] < pivot1
+ * pivot1 <= all in (k, upper) <= pivot2
+ * all in [upper, end) > pivot2
*
- * Pointer k is the first index of ?-part.
+ * Pointer k is the last index of ?-part
*/
- outer:
- 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
- while (a[great] > pivot2) {
- if (great-- == k) {
- break outer;
- }
- }
- 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;
- }
- }
-
- // 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 > 4/7 of the array),
- * swap internal pivot values to ends.
- */
- if (less < e1 && e5 < great) {
- /*
- * Skip elements, which are equal to pivot values.
- */
- while (a[less] == pivot1) {
- ++less;
- }
-
- while (a[great] == pivot2) {
- --great;
- }
-
- /*
- * Partitioning:
- *
- * left part center part right part
- * +----------------------------------------------------------+
- * | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 |
- * +----------------------------------------------------------+
- * ^ ^ ^
- * | | |
- * less k great
- *
- * Invariants:
- *
- * all in (*, less) == pivot1
- * pivot1 < all in [less, k) < pivot2
- * all in (great, *) == pivot2
- *
- * Pointer k is the first index of ?-part.
- */
- outer:
- for (int k = less - 1; ++k <= great; ) {
- short 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[great] < pivot2
- 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 $ = --lower, k = ++upper; --k > lower; ) {
+ char ak = a[k];
+
+ if (ak < pivot1) { // Move a[k] to the left side
+ while (a[++lower] < pivot1);
+
+ if (lower > k) {
+ lower = k;
+ break;
}
+ if (a[lower] > pivot2) { // a[lower] >= pivot1
+ a[k] = a[--upper];
+ a[upper] = a[lower];
+ } else { // pivot1 <= a[lower] <= pivot2
+ a[k] = a[lower];
+ }
+ a[lower] = ak;
+ } else if (ak > pivot2) { // Move a[k] to the right side
+ a[k] = a[--upper];
+ a[upper] = ak;
}
}
- // Sort center part recursively
- sort(a, less, great, false);
+ /*
+ * Swap the pivots into their final positions.
+ */
+ a[low] = a[lower]; a[lower] = pivot1;
+ a[end] = a[upper]; a[upper] = pivot2;
+ /*
+ * Sort all parts recursively, excluding known pivots.
+ */
+ if (parallel && length > PARALLEL_QUICKSORT_THRESHOLD) {
+ ForkJoinTask.invokeAll(
+ new Sorter(a, bits | 1, lower + 1, upper),
+ new Sorter(a, bits | 1, upper + 1, high),
+ new Sorter(a, bits, low, lower)
+ );
+ } else {
+ sort(a, bits | 1, false, upper + 1, high);
+ sort(a, bits, false, low, lower);
+ sort(a, bits | 1, false, lower + 1, upper);
+ }
} else { // Partitioning with one pivot
+
/*
- * Use the third of the five sorted elements as pivot.
- * This value is inexpensive approximation of the median.
+ * Use the third element as the pivot. This value
+ * is inexpensive approximation of the median.
*/
- short pivot = a[e3];
+ char pivot = a[e3];
/*
- * Partitioning degenerates to the traditional 3-way
- * (or "Dutch National Flag") schema:
- *
- * left part center part right part
- * +-------------------------------------------------+
- * | < pivot | == pivot | ? | > pivot |
- * +-------------------------------------------------+
- * ^ ^ ^
- * | | |
- * less k great
+ * The first element to be sorted is moved to the location
+ * formerly occupied by the pivot. When partitioning is
+ * completed, the pivot is swapped back into its final
+ * position, and excluded from subsequent sorting.
+ */
+ a[e3] = a[lower];
+
+ /*
+ * Traditional 3-way (Dutch National Flag) partitioning
+ *
+ * left part central part right part
+ * +------------------------------------------------------+
+ * | < pivot | ? | == pivot | > pivot |
+ * +------------------------------------------------------+
+ * ^ ^ ^
+ * | | |
+ * lower k upper
*
* Invariants:
*
- * all in (left, less) < pivot
- * all in [less, k) == pivot
- * all in (great, right) > pivot
+ * all in (low, lower] < pivot
+ * all in (k, upper) == pivot
+ * all in [upper, end] > pivot
*
- * Pointer k is the first index of ?-part.
+ * Pointer k is the last index of ?-part
*/
- for (int k = less; k <= great; ++k) {
+ for (int k = ++upper; --k > lower; ) {
if (a[k] == pivot) {
continue;
}
- short ak = a[k];
- if (ak < pivot) { // Move a[k] to left part
- a[k] = a[less];
- a[less] = ak;
- ++less;
- } else { // a[k] > pivot - Move a[k] to right part
- while (a[great] > pivot) {
- --great;
- }
- if (a[great] < pivot) { // a[great] <= pivot
- a[k] = a[less];
- a[less] = a[great];
- ++less;
- } else { // a[great] == pivot
- /*
- * Even though a[great] equals to pivot, the
- * assignment a[k] = pivot may be incorrect,
- * if a[great] and pivot 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] = pivot;
+ char ak = a[k];
+
+ if (ak < pivot) { // Move a[k] to the left side
+ while (a[++lower] < pivot);
+
+ if (lower > k) {
+ lower = k;
+ break;
+ }
+ a[k] = pivot;
+
+ if (a[lower] > pivot) {
+ a[--upper] = a[lower];
}
- a[great] = ak;
- --great;
+ a[lower] = ak;
+ } else { // ak > pivot - Move a[k] to the right side
+ a[k] = pivot;
+ a[--upper] = ak;
}
}
/*
- * Sort left and right parts recursively.
- * All elements from center part are equal
+ * Swap the pivot into its final position.
+ */
+ a[low] = a[lower]; a[lower] = pivot;
+
+ /*
+ * Sort the left and the right parts recursively, excluding
+ * known pivot. All elements from the central part are equal
* and, therefore, already sorted.
*/
- sort(a, left, less - 1, leftmost);
- sort(a, great + 1, right, false);
+ if (parallel && length > PARALLEL_QUICKSORT_THRESHOLD) {
+ ForkJoinTask.invokeAll(
+ new Sorter(a, bits, low, lower),
+ new Sorter(a, bits | 1, upper, high)
+ );
+ } else {
+ sort(a, bits | 1, false, upper, high);
+ sort(a, bits, false, low, lower);
+ }
}
}
/**
- * Sorts the specified range of the array using the given
- * workspace array slice if possible for merging
+ * Sorts the specified range of the array.
*
* @param a the array to be sorted
- * @param left the index of the first element, inclusive, to be sorted
- * @param right the index of the last element, inclusive, to be sorted
- * @param work a workspace array (slice)
- * @param workBase origin of usable space in work array
- * @param workLen usable size of work array
- */
- static void sort(char[] a, int left, int right,
- char[] work, int workBase, int workLen) {
- // 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 - 1; ++i <= right;
- count[a[i]]++
- );
- for (int i = NUM_CHAR_VALUES, k = right + 1; k > left; ) {
- while (count[--i] == 0);
- char value = (char) i;
- int s = count[i];
-
- do {
- a[--k] = value;
- } while (--s > 0);
- }
- } else { // Use Dual-Pivot Quicksort on small arrays
- doSort(a, left, right, work, workBase, workLen);
+ * @param parallel indicates whether sorting is performed in parallel
+ * @param low the index of the first element, inclusive, to be sorted
+ * @param high the index of the last element, exclusive, to be sorted
+ */
+ static void sort(short[] a, boolean parallel, int low, int high) {
+ if (high - low > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) {
+ SortingAlgorithms.countingSort(a, low, high);
+ } else {
+ sort(a, LEFTMOST_BITS, parallel, low, high);
}
}
- /** The number of distinct char values. */
- private static final int NUM_CHAR_VALUES = 1 << 16;
-
/**
- * Sorts the specified range of the array.
+ * Sorts the specified range of the array by the 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 work a workspace array (slice)
- * @param workBase origin of usable space in work array
- * @param workLen usable size of work array
- */
- private static void doSort(char[] a, int left, int right,
- char[] work, int workBase, int workLen) {
- // Use Quicksort on small arrays
- if (right - left < QUICKSORT_THRESHOLD) {
- sort(a, left, right, true);
- return;
- }
+ * @param bits the recursion depth of Quicksort and the leftmost flag
+ * @param parallel indicates whether sorting is performed in parallel
+ * @param low the index of the first element, inclusive, to be sorted
+ * @param high the index of the last element, exclusive, to be sorted
+ */
+ private static void sort(short[] a, int bits, boolean parallel, int low, int high) {
+ int end = high - 1, length = high - low;
/*
- * Index run[i] is the start of i-th run
- * (ascending or descending sequence).
+ * Run insertion sorts on non-leftmost part.
*/
- int[] run = new int[MAX_RUN_COUNT + 1];
- int count = 0; run[0] = left;
-
- // Check if the array is nearly sorted
- for (int k = left; k < right; run[count] = k) {
- // Equal items in the beginning of the sequence
- while (k < right && a[k] == a[k + 1])
- k++;
- if (k == right) break; // Sequence finishes with equal items
- if (a[k] < a[k + 1]) { // ascending
- while (++k <= right && a[k - 1] <= a[k]);
- } else if (a[k] > a[k + 1]) { // descending
- while (++k <= right && a[k - 1] >= a[k]);
- // Transform into an ascending sequence
- for (int lo = run[count] - 1, hi = k; ++lo < --hi; ) {
- char t = a[lo]; a[lo] = a[hi]; a[hi] = t;
- }
- }
+ if ((bits & 1) > 0) {
- // Merge a transformed descending sequence followed by an
- // ascending sequence
- if (run[count] > left && a[run[count]] >= a[run[count] - 1]) {
- count--;
+ /*
+ * Use nano insertion sort on tiny part.
+ */
+ if (length < NANO_INSERTION_SORT_THRESHOLD) {
+ SortingAlgorithms.nanoInsertionSort(a, low, high);
+ return;
}
/*
- * The array is not highly structured,
- * use Quicksort instead of merge sort.
+ * Use pair insertion sort on small part.
*/
- if (++count == MAX_RUN_COUNT) {
- sort(a, left, right, true);
+ if (length < PAIR_INSERTION_SORT_THRESHOLD) {
+ SortingAlgorithms.pairInsertionSort(a, low, end);
return;
}
}
- // These invariants should hold true:
- // run[0] = 0
- // run[] = right + 1; (terminator)
-
- if (count == 0) {
- // A single equal run
- return;
- } else if (count == 1 && run[count] > right) {
- // Either a single ascending or a transformed descending run.
- // Always check that a final run is a proper terminator, otherwise
- // we have an unterminated trailing run, to handle downstream.
+ /*
+ * Switch to heap sort on the leftmost part or
+ * if the execution time is becoming quadratic.
+ */
+ if (length < HEAP_SORT_THRESHOLD || (bits -= 2) < 0) {
+ SortingAlgorithms.heapSort(a, low, end);
return;
}
- right++;
- if (run[count] < right) {
- // Corner case: the final run is not a terminator. This may happen
- // if a final run is an equals run, or there is a single-element run
- // at the end. Fix up by adding a proper terminator at the end.
- // Note that we terminate with (right + 1), incremented earlier.
- run[++count] = right;
- }
-
- // Determine alternation base for merge
- byte odd = 0;
- for (int n = 1; (n <<= 1) < count; odd ^= 1);
-
- // Use or create temporary array b for merging
- char[] b; // temp array; alternates with a
- int ao, bo; // array offsets from 'left'
- int blen = right - left; // space needed for b
- if (work == null || workLen < blen || workBase + blen > work.length) {
- work = new char[blen];
- workBase = 0;
- }
- if (odd == 0) {
- System.arraycopy(a, left, work, workBase, blen);
- b = a;
- bo = 0;
- a = work;
- ao = workBase - left;
- } else {
- b = work;
- ao = 0;
- bo = workBase - left;
- }
-
- // Merging
- for (int last; count > 1; count = last) {
- for (int k = (last = 0) + 2; k <= count; k += 2) {
- int hi = run[k], mi = run[k - 1];
- for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) {
- if (q >= hi || p < mi && a[p + ao] <= a[q + ao]) {
- b[i + bo] = a[p++ + ao];
- } else {
- b[i + bo] = a[q++ + ao];
- }
- }
- run[++last] = hi;
- }
- if ((count & 1) != 0) {
- for (int i = right, lo = run[count - 1]; --i >= lo;
- b[i + bo] = a[i + ao]
- );
- run[++last] = right;
- }
- char[] t = a; a = b; b = t;
- int o = ao; ao = bo; bo = o;
- }
- }
-
- /**
- * Sorts the specified range of the array by Dual-Pivot Quicksort.
- *
- * @param a the array to be sorted
- * @param left the index of the first element, inclusive, to be sorted
- * @param right the index of the last element, inclusive, to be sorted
- * @param leftmost indicates if this part is the leftmost in the range
- */
- private static void sort(char[] 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) {
- /*
- * 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];
- while (ai < a[j]) {
- a[j + 1] = a[j];
- if (j-- == left) {
- break;
- }
- }
- a[j + 1] = ai;
- }
- } else {
- /*
- * Skip the longest ascending sequence.
- */
- do {
- if (left >= right) {
- return;
- }
- } while (a[++left] >= a[left - 1]);
-
- /*
- * 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 more optimized algorithm, so called pair insertion
- * sort, which is faster (in the context of Quicksort)
- * than traditional implementation of insertion sort.
- */
- for (int k = left; ++left <= right; k = ++left) {
- char a1 = a[k], a2 = a[left];
-
- if (a1 < a2) {
- a2 = a1; a1 = 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;
- }
+ /*
+ * Check if the array is nearly sorted
+ * and then try to sort it by Merging sort.
+ */
+ if (SortingAlgorithms.mergingSort(a, parallel, low, high)) {
return;
}
- // Inexpensive approximation of length / 7
- int seventh = (length >> 3) + (length >> 6) + 1;
+ /*
+ * The splitting of the array, defined by the following
+ * step, is related to the inexpensive approximation of
+ * the golden ratio.
+ */
+ int step = (length >> 3) * 3 + 3;
/*
- * 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.
+ * Five elements around (and including) the central element in
+ * the array will be used for pivot selection as described below.
+ * The unequal choice of 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;
+ int e1 = low + step;
+ int e5 = end - step;
+ int e3 = (e1 + e5) >>> 1;
+ int e2 = (e1 + e3) >>> 1;
+ int e4 = (e3 + e5) >>> 1;
- // Sort these elements using insertion sort
- if (a[e2] < a[e1]) { char t = a[e2]; a[e2] = a[e1]; a[e1] = t; }
+ /*
+ * Sort these elements in place by the combination
+ * of 5-element sorting network and insertion sort.
+ */
+ if (a[e5] < a[e3]) { short t = a[e5]; a[e5] = a[e3]; a[e3] = t; }
+ if (a[e4] < a[e2]) { short t = a[e4]; a[e4] = a[e2]; a[e2] = t; }
+ if (a[e5] < a[e4]) { short t = a[e5]; a[e5] = a[e4]; a[e4] = t; }
+ if (a[e3] < a[e2]) { short t = a[e3]; a[e3] = a[e2]; a[e2] = t; }
+ if (a[e4] < a[e3]) { short t = a[e4]; a[e4] = a[e3]; a[e3] = 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]) { 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]) { 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; }
+ if (a[e1] > a[e2]) { short t = a[e1]; a[e1] = a[e2]; a[e2] = t;
+ if (t > a[e3]) { a[e2] = a[e3]; a[e3] = t;
+ if (t > a[e4]) { a[e3] = a[e4]; a[e4] = t;
+ if (t > a[e5]) { a[e4] = a[e5]; a[e5] = t; }
}
}
}
// 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
+ int lower = low; // The index of the last element of the left part
+ int upper = end; // The index of the first element of the right part
+
+ if (a[e1] < a[e2] && a[e2] < a[e3] && a[e3] < a[e4] && a[e4] < a[e5]) {
- if (a[e1] != a[e2] && a[e2] != a[e3] && a[e3] != a[e4] && a[e4] != a[e5]) {
/*
- * Use the second and fourth of the five sorted elements as pivots.
- * These values are inexpensive approximations of the first and
- * second terciles of the array. Note that pivot1 <= pivot2.
+ * Use the first and the fifth elements as the pivots.
+ * These values are inexpensive approximation of tertiles.
+ * Note, that pivot1 < pivot2.
*/
- char pivot1 = a[e2];
- char pivot2 = a[e4];
+ short pivot1 = a[e1];
+ short pivot2 = a[e5];
/*
* 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
+ * is completed, the pivots are swapped back into their final
* positions, and excluded from subsequent sorting.
*/
- a[e2] = a[left];
- a[e4] = a[right];
+ a[e1] = a[lower];
+ a[e5] = a[upper];
/*
- * Skip elements, which are less or greater than pivot values.
+ * Skip elements, which are less or greater than the pivots.
*/
- while (a[++less] < pivot1);
- while (a[--great] > pivot2);
+ while (a[++lower] < pivot1);
+ while (a[--upper] > pivot2);
/*
- * Partitioning:
+ * Backwards 3-interval partitioning
*
- * left part center part right part
- * +--------------------------------------------------------------+
- * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 |
- * +--------------------------------------------------------------+
- * ^ ^ ^
- * | | |
- * less k great
+ * left part central part right part
+ * +------------------------------------------------------------+
+ * | < pivot1 | ? | pivot1 <= && <= pivot2 | > pivot2 |
+ * +------------------------------------------------------------+
+ * ^ ^ ^
+ * | | |
+ * lower k upper
*
* Invariants:
*
- * all in (left, less) < pivot1
- * pivot1 <= all in [less, k) <= pivot2
- * all in (great, right) > pivot2
+ * all in (low, lower] < pivot1
+ * pivot1 <= all in (k, upper) <= pivot2
+ * all in [upper, end) > pivot2
*
- * Pointer k is the first index of ?-part.
+ * Pointer k is the last index of ?-part
*/
- outer:
- 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
- while (a[great] > pivot2) {
- if (great-- == k) {
- break outer;
- }
- }
- 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;
- }
- }
-
- // 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 > 4/7 of the array),
- * swap internal pivot values to ends.
- */
- if (less < e1 && e5 < great) {
- /*
- * Skip elements, which are equal to pivot values.
- */
- while (a[less] == pivot1) {
- ++less;
- }
-
- while (a[great] == pivot2) {
- --great;
- }
-
- /*
- * Partitioning:
- *
- * left part center part right part
- * +----------------------------------------------------------+
- * | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 |
- * +----------------------------------------------------------+
- * ^ ^ ^
- * | | |
- * less k great
- *
- * Invariants:
- *
- * all in (*, less) == pivot1
- * pivot1 < all in [less, k) < pivot2
- * all in (great, *) == pivot2
- *
- * Pointer k is the first index of ?-part.
- */
- outer:
- for (int k = less - 1; ++k <= great; ) {
- char 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[great] < pivot2
- 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 $ = --lower, k = ++upper; --k > lower; ) {
+ short ak = a[k];
+
+ if (ak < pivot1) { // Move a[k] to the left side
+ while (a[++lower] < pivot1);
+
+ if (lower > k) {
+ lower = k;
+ break;
}
+ if (a[lower] > pivot2) { // a[lower] >= pivot1
+ a[k] = a[--upper];
+ a[upper] = a[lower];
+ } else { // pivot1 <= a[lower] <= pivot2
+ a[k] = a[lower];
+ }
+ a[lower] = ak;
+ } else if (ak > pivot2) { // Move a[k] to the right side
+ a[k] = a[--upper];
+ a[upper] = ak;
}
}
- // Sort center part recursively
- sort(a, less, great, false);
+ /*
+ * Swap the pivots into their final positions.
+ */
+ a[low] = a[lower]; a[lower] = pivot1;
+ a[end] = a[upper]; a[upper] = pivot2;
+ /*
+ * Sort all parts recursively, excluding known pivots.
+ */
+ if (parallel && length > PARALLEL_QUICKSORT_THRESHOLD) {
+ ForkJoinTask.invokeAll(
+ new Sorter(a, bits | 1, lower + 1, upper),
+ new Sorter(a, bits | 1, upper + 1, high),
+ new Sorter(a, bits, low, lower)
+ );
+ } else {
+ sort(a, bits | 1, false, upper + 1, high);
+ sort(a, bits, false, low, lower);
+ sort(a, bits | 1, false, lower + 1, upper);
+ }
} else { // Partitioning with one pivot
+
/*
- * Use the third of the five sorted elements as pivot.
- * This value is inexpensive approximation of the median.
+ * Use the third element as the pivot. This value
+ * is inexpensive approximation of the median.
*/
- char pivot = a[e3];
+ short pivot = a[e3];
/*
- * Partitioning degenerates to the traditional 3-way
- * (or "Dutch National Flag") schema:
- *
- * left part center part right part
- * +-------------------------------------------------+
- * | < pivot | == pivot | ? | > pivot |
- * +-------------------------------------------------+
- * ^ ^ ^
- * | | |
- * less k great
+ * The first element to be sorted is moved to the location
+ * formerly occupied by the pivot. When partitioning is
+ * completed, the pivot is swapped back into its final
+ * position, and excluded from subsequent sorting.
+ */
+ a[e3] = a[lower];
+
+ /*
+ * Traditional 3-way (Dutch National Flag) partitioning
+ *
+ * left part central part right part
+ * +------------------------------------------------------+
+ * | < pivot | ? | == pivot | > pivot |
+ * +------------------------------------------------------+
+ * ^ ^ ^
+ * | | |
+ * lower k upper
*
* Invariants:
*
- * all in (left, less) < pivot
- * all in [less, k) == pivot
- * all in (great, right) > pivot
+ * all in (low, lower] < pivot
+ * all in (k, upper) == pivot
+ * all in [upper, end] > pivot
*
- * Pointer k is the first index of ?-part.
+ * Pointer k is the last index of ?-part
*/
- for (int k = less; k <= great; ++k) {
+ for (int k = ++upper; --k > lower; ) {
if (a[k] == pivot) {
continue;
}
- char ak = a[k];
- if (ak < pivot) { // Move a[k] to left part
- a[k] = a[less];
- a[less] = ak;
- ++less;
- } else { // a[k] > pivot - Move a[k] to right part
- while (a[great] > pivot) {
- --great;
- }
- if (a[great] < pivot) { // a[great] <= pivot
- a[k] = a[less];
- a[less] = a[great];
- ++less;
- } else { // a[great] == pivot
- /*
- * Even though a[great] equals to pivot, the
- * assignment a[k] = pivot may be incorrect,
- * if a[great] and pivot 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] = pivot;
+ short ak = a[k];
+
+ if (ak < pivot) { // Move a[k] to the left side
+ while (a[++lower] < pivot);
+
+ if (lower > k) {
+ lower = k;
+ break;
+ }
+ a[k] = pivot;
+
+ if (a[lower] > pivot) {
+ a[--upper] = a[lower];
}
- a[great] = ak;
- --great;
+ a[lower] = ak;
+ } else { // ak > pivot - Move a[k] to the right side
+ a[k] = pivot;
+ a[--upper] = ak;
}
}
/*
- * Sort left and right parts recursively.
- * All elements from center part are equal
- * and, therefore, already sorted.
+ * Swap the pivot into its final position.
*/
- sort(a, left, less - 1, leftmost);
- sort(a, great + 1, right, false);
- }
- }
+ a[low] = a[lower]; a[lower] = pivot;
- /** The number of distinct byte values. */
- private static final int NUM_BYTE_VALUES = 1 << 8;
-
- /**
- * 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
- */
- 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;
+ /*
+ * Sort the left and the right parts recursively, excluding
+ * known pivot. All elements from the central part are equal
+ * and, therefore, already sorted.
+ */
+ if (parallel && length > PARALLEL_QUICKSORT_THRESHOLD) {
+ ForkJoinTask.invokeAll(
+ new Sorter(a, bits, low, lower),
+ new Sorter(a, bits | 1, upper, high)
+ );
+ } else {
+ sort(a, bits | 1, false, upper, high);
+ sort(a, bits, false, low, lower);
}
}
}
/**
- * Sorts the specified range of the array using the given
- * workspace array slice if possible for merging
+ * Sorts the specified range of the array.
*
* @param a the array to be sorted
- * @param left the index of the first element, inclusive, to be sorted
- * @param right the index of the last element, inclusive, to be sorted
- * @param work a workspace array (slice)
- * @param workBase origin of usable space in work array
- * @param workLen usable size of work array
+ * @param parallel indicates whether sorting is performed in parallel
+ * @param low the index of the first element, inclusive, to be sorted
+ * @param high the index of the last element, exclusive, to be sorted
*/
- static void sort(float[] a, int left, int right,
- float[] work, int workBase, int workLen) {
+ static void sort(float[] a, boolean parallel, int low, int high) {
/*
- * Phase 1: Move NaNs to the end of the array.
+ * Phase 1. Count the number of negative zero -0.0f,
+ * turn them into positive zero, and move all NaNs
+ * to the end of the array.
*/
- while (left <= right && Float.isNaN(a[right])) {
- --right;
- }
- for (int k = right; --k >= left; ) {
- float ak = a[k];
- if (ak != ak) { // a[k] is NaN
- a[k] = a[right];
- a[right] = ak;
- --right;
+ int numNegativeZero = 0;
+
+ for (int k = high; k > low; ) {
+ float ak = a[--k];
+
+ if (ak == 0.0f && Float.floatToRawIntBits(ak) < 0) { // ak is -0.0f
+ numNegativeZero += 1;
+ a[k] = 0.0f;
+ } else if (ak != ak) { // ak is NaN
+ a[k] = a[--high];
+ a[high] = ak;
}
}
/*
- * Phase 2: Sort everything except NaNs (which are already in place).
+ * Phase 2. Sort everything except NaNs,
+ * which are already in place.
*/
- doSort(a, left, right, work, workBase, workLen);
+ sort(a, LEFTMOST_BITS, parallel, low, high);
/*
- * Phase 3: Place negative zeros before positive zeros.
+ * Phase 3. Turn positive zero 0.0f
+ * back into negative zero -0.0f.
*/
- int hi = right;
+ if (++numNegativeZero == 1) {
+ return;
+ }
/*
- * Find the first zero, or first positive, or last negative element.
+ * Find the position one less than
+ * the index of the first zero.
*/
- while (left < hi) {
- int middle = (left + hi) >>> 1;
- float middleValue = a[middle];
+ while (low <= high) {
+ int middle = (low + high) >>> 1;
- if (middleValue < 0.0f) {
- left = middle + 1;
+ if (a[middle] < 0) {
+ low = middle + 1;
} else {
- hi = middle;
+ high = middle - 1;
}
}
/*
- * Skip the last negative value (if any) or all leading negative zeros.
- */
- while (left <= right && Float.floatToRawIntBits(a[left]) < 0) {
- ++left;
- }
-
- /*
- * Move negative zeros to the beginning of the sub-range.
- *
- * Partitioning:
- *
- * +----------------------------------------------------+
- * | < 0.0 | -0.0 | 0.0 | ? ( >= 0.0 ) |
- * +----------------------------------------------------+
- * ^ ^ ^
- * | | |
- * left p k
- *
- * Invariants:
- *
- * all in (*, left) < 0.0
- * all in [left, p) == -0.0
- * all in [p, k) == 0.0
- * all in [k, right] >= 0.0
- *
- * Pointer k is the first index of ?-part.
+ * Replace the required number of 0.0f by -0.0f.
*/
- 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;
- }
+ while (--numNegativeZero > 0) {
+ a[++high] = -0.0f;
}
}
/**
- * Sorts the specified range of the array.
+ * Sorts the specified range of the array by the 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 work a workspace array (slice)
- * @param workBase origin of usable space in work array
- * @param workLen usable size of work array
- */
- private static void doSort(float[] a, int left, int right,
- float[] work, int workBase, int workLen) {
- // Use Quicksort on small arrays
- if (right - left < QUICKSORT_THRESHOLD) {
- sort(a, left, right, true);
- return;
- }
+ * @param bits the recursion depth of Quicksort and the leftmost flag
+ * @param parallel indicates whether sorting is performed in parallel
+ * @param low the index of the first element, inclusive, to be sorted
+ * @param high the index of the last element, exclusive, to be sorted
+ */
+ private static void sort(float[] a, int bits, boolean parallel, int low, int high) {
+ int end = high - 1, length = high - low;
/*
- * Index run[i] is the start of i-th run
- * (ascending or descending sequence).
+ * Run insertion sorts on non-leftmost part.
*/
- int[] run = new int[MAX_RUN_COUNT + 1];
- int count = 0; run[0] = left;
-
- // Check if the array is nearly sorted
- for (int k = left; k < right; run[count] = k) {
- // Equal items in the beginning of the sequence
- while (k < right && a[k] == a[k + 1])
- k++;
- if (k == right) break; // Sequence finishes with equal items
- if (a[k] < a[k + 1]) { // ascending
- while (++k <= right && a[k - 1] <= a[k]);
- } else if (a[k] > a[k + 1]) { // descending
- while (++k <= right && a[k - 1] >= a[k]);
- // Transform into an ascending sequence
- for (int lo = run[count] - 1, hi = k; ++lo < --hi; ) {
- float t = a[lo]; a[lo] = a[hi]; a[hi] = t;
- }
- }
+ if ((bits & 1) > 0) {
- // Merge a transformed descending sequence followed by an
- // ascending sequence
- if (run[count] > left && a[run[count]] >= a[run[count] - 1]) {
- count--;
+ /*
+ * Use nano insertion sort on tiny part.
+ */
+ if (length < NANO_INSERTION_SORT_THRESHOLD) {
+ SortingAlgorithms.nanoInsertionSort(a, low, high);
+ return;
}
/*
- * The array is not highly structured,
- * use Quicksort instead of merge sort.
+ * Use pair insertion sort on small part.
*/
- if (++count == MAX_RUN_COUNT) {
- sort(a, left, right, true);
+ if (length < PAIR_INSERTION_SORT_THRESHOLD) {
+ SortingAlgorithms.pairInsertionSort(a, low, end);
return;
}
}
- // These invariants should hold true:
- // run[0] = 0
- // run[] = right + 1; (terminator)
-
- if (count == 0) {
- // A single equal run
- return;
- } else if (count == 1 && run[count] > right) {
- // Either a single ascending or a transformed descending run.
- // Always check that a final run is a proper terminator, otherwise
- // we have an unterminated trailing run, to handle downstream.
+ /*
+ * Switch to heap sort on the leftmost part or
+ * if the execution time is becoming quadratic.
+ */
+ if (length < HEAP_SORT_THRESHOLD || (bits -= 2) < 0) {
+ SortingAlgorithms.heapSort(a, low, end);
return;
}
- right++;
- if (run[count] < right) {
- // Corner case: the final run is not a terminator. This may happen
- // if a final run is an equals run, or there is a single-element run
- // at the end. Fix up by adding a proper terminator at the end.
- // Note that we terminate with (right + 1), incremented earlier.
- run[++count] = right;
- }
-
- // Determine alternation base for merge
- byte odd = 0;
- for (int n = 1; (n <<= 1) < count; odd ^= 1);
-
- // Use or create temporary array b for merging
- float[] b; // temp array; alternates with a
- int ao, bo; // array offsets from 'left'
- int blen = right - left; // space needed for b
- if (work == null || workLen < blen || workBase + blen > work.length) {
- work = new float[blen];
- workBase = 0;
- }
- if (odd == 0) {
- System.arraycopy(a, left, work, workBase, blen);
- b = a;
- bo = 0;
- a = work;
- ao = workBase - left;
- } else {
- b = work;
- ao = 0;
- bo = workBase - left;
- }
-
- // Merging
- for (int last; count > 1; count = last) {
- for (int k = (last = 0) + 2; k <= count; k += 2) {
- int hi = run[k], mi = run[k - 1];
- for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) {
- if (q >= hi || p < mi && a[p + ao] <= a[q + ao]) {
- b[i + bo] = a[p++ + ao];
- } else {
- b[i + bo] = a[q++ + ao];
- }
- }
- run[++last] = hi;
- }
- if ((count & 1) != 0) {
- for (int i = right, lo = run[count - 1]; --i >= lo;
- b[i + bo] = a[i + ao]
- );
- run[++last] = right;
- }
- float[] t = a; a = b; b = t;
- int o = ao; ao = bo; bo = o;
- }
- }
-
- /**
- * Sorts the specified range of the array by Dual-Pivot Quicksort.
- *
- * @param a the array to be sorted
- * @param left the index of the first element, inclusive, to be sorted
- * @param right the index of the last element, inclusive, to be sorted
- * @param leftmost indicates if this part is the leftmost in the range
- */
- private static void sort(float[] 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) {
- /*
- * 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];
- while (ai < a[j]) {
- a[j + 1] = a[j];
- if (j-- == left) {
- break;
- }
- }
- a[j + 1] = ai;
- }
- } else {
- /*
- * Skip the longest ascending sequence.
- */
- do {
- if (left >= right) {
- return;
- }
- } while (a[++left] >= a[left - 1]);
-
- /*
- * 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 more optimized algorithm, so called pair insertion
- * sort, which is faster (in the context of Quicksort)
- * than traditional implementation of insertion sort.
- */
- for (int k = left; ++left <= right; k = ++left) {
- float a1 = a[k], a2 = a[left];
-
- if (a1 < a2) {
- a2 = a1; a1 = 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;
- }
+ /*
+ * Check if the array is nearly sorted
+ * and then try to sort it by Merging sort.
+ */
+ if (SortingAlgorithms.mergingSort(a, parallel, low, high)) {
return;
}
- // Inexpensive approximation of length / 7
- int seventh = (length >> 3) + (length >> 6) + 1;
+ /*
+ * The splitting of the array, defined by the following
+ * step, is related to the inexpensive approximation of
+ * the golden ratio.
+ */
+ int step = (length >> 3) * 3 + 3;
/*
- * 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.
+ * Five elements around (and including) the central element in
+ * the array will be used for pivot selection as described below.
+ * The unequal choice of 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;
+ int e1 = low + step;
+ int e5 = end - step;
+ int e3 = (e1 + e5) >>> 1;
+ int e2 = (e1 + e3) >>> 1;
+ int e4 = (e3 + e5) >>> 1;
- // Sort these elements using insertion sort
- if (a[e2] < a[e1]) { float t = a[e2]; a[e2] = a[e1]; a[e1] = t; }
+ /*
+ * Sort these elements in place by the combination
+ * of 5-element sorting network and insertion sort.
+ */
+ if (a[e5] < a[e3]) { float t = a[e5]; a[e5] = a[e3]; a[e3] = t; }
+ if (a[e4] < a[e2]) { float t = a[e4]; a[e4] = a[e2]; a[e2] = t; }
+ if (a[e5] < a[e4]) { float t = a[e5]; a[e5] = a[e4]; a[e4] = t; }
+ if (a[e3] < a[e2]) { float t = a[e3]; a[e3] = a[e2]; a[e2] = t; }
+ if (a[e4] < a[e3]) { float t = a[e4]; a[e4] = a[e3]; a[e3] = t; }
- if (a[e3] < a[e2]) { float 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]) { float 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]) { float 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; }
+ if (a[e1] > a[e2]) { float t = a[e1]; a[e1] = a[e2]; a[e2] = t;
+ if (t > a[e3]) { a[e2] = a[e3]; a[e3] = t;
+ if (t > a[e4]) { a[e3] = a[e4]; a[e4] = t;
+ if (t > a[e5]) { a[e4] = a[e5]; a[e5] = t; }
}
}
}
// 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
+ int lower = low; // The index of the last element of the left part
+ int upper = end; // The index of the first element of the right part
+
+ if (a[e1] < a[e2] && a[e2] < a[e3] && a[e3] < a[e4] && a[e4] < a[e5]) {
- if (a[e1] != a[e2] && a[e2] != a[e3] && a[e3] != a[e4] && a[e4] != a[e5]) {
/*
- * Use the second and fourth of the five sorted elements as pivots.
- * These values are inexpensive approximations of the first and
- * second terciles of the array. Note that pivot1 <= pivot2.
+ * Use the first and the fifth elements as the pivots.
+ * These values are inexpensive approximation of tertiles.
+ * Note, that pivot1 < pivot2.
*/
- float pivot1 = a[e2];
- float pivot2 = a[e4];
+ float pivot1 = a[e1];
+ float pivot2 = a[e5];
/*
* 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
+ * is completed, the pivots are swapped back into their final
* positions, and excluded from subsequent sorting.
*/
- a[e2] = a[left];
- a[e4] = a[right];
+ a[e1] = a[lower];
+ a[e5] = a[upper];
/*
- * Skip elements, which are less or greater than pivot values.
+ * Skip elements, which are less or greater than the pivots.
*/
- while (a[++less] < pivot1);
- while (a[--great] > pivot2);
+ while (a[++lower] < pivot1);
+ while (a[--upper] > pivot2);
/*
- * Partitioning:
+ * Backwards 3-interval partitioning
*
- * left part center part right part
- * +--------------------------------------------------------------+
- * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 |
- * +--------------------------------------------------------------+
- * ^ ^ ^
- * | | |
- * less k great
+ * left part central part right part
+ * +------------------------------------------------------------+
+ * | < pivot1 | ? | pivot1 <= && <= pivot2 | > pivot2 |
+ * +------------------------------------------------------------+
+ * ^ ^ ^
+ * | | |
+ * lower k upper
*
* Invariants:
*
- * all in (left, less) < pivot1
- * pivot1 <= all in [less, k) <= pivot2
- * all in (great, right) > pivot2
+ * all in (low, lower] < pivot1
+ * pivot1 <= all in (k, upper) <= pivot2
+ * all in [upper, end) > pivot2
*
- * Pointer k is the first index of ?-part.
+ * Pointer k is the last index of ?-part
*/
- outer:
- for (int k = less - 1; ++k <= great; ) {
+ for (int $ = --lower, k = ++upper; --k > lower; ) {
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
- while (a[great] > pivot2) {
- if (great-- == k) {
- break outer;
- }
- }
- 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;
- }
- }
-
- // 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 > 4/7 of the array),
- * swap internal pivot values to ends.
- */
- if (less < e1 && e5 < great) {
- /*
- * Skip elements, which are equal to pivot values.
- */
- while (a[less] == pivot1) {
- ++less;
- }
-
- while (a[great] == pivot2) {
- --great;
- }
-
- /*
- * Partitioning:
- *
- * left part center part right part
- * +----------------------------------------------------------+
- * | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 |
- * +----------------------------------------------------------+
- * ^ ^ ^
- * | | |
- * less k great
- *
- * Invariants:
- *
- * all in (*, less) == pivot1
- * pivot1 < all in [less, k) < pivot2
- * all in (great, *) == pivot2
- *
- * Pointer k is the first index of ?-part.
- */
- outer:
- for (int k = less - 1; ++k <= great; ) {
- float 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[great] < pivot2
- 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] = a[great];
- ++less;
- } else { // pivot1 < a[great] < pivot2
- a[k] = a[great];
- }
- a[great] = ak;
- --great;
+
+ if (ak < pivot1) { // Move a[k] to the left side
+ while (a[++lower] < pivot1);
+
+ if (lower > k) {
+ lower = k;
+ break;
+ }
+ if (a[lower] > pivot2) { // a[lower] >= pivot1
+ a[k] = a[--upper];
+ a[upper] = a[lower];
+ } else { // pivot1 <= a[lower] <= pivot2
+ a[k] = a[lower];
}
+ a[lower] = ak;
+ } else if (ak > pivot2) { // Move a[k] to the right side
+ a[k] = a[--upper];
+ a[upper] = ak;
}
}
- // Sort center part recursively
- sort(a, less, great, false);
+ /*
+ * Swap the pivots into their final positions.
+ */
+ a[low] = a[lower]; a[lower] = pivot1;
+ a[end] = a[upper]; a[upper] = pivot2;
+ /*
+ * Sort all parts recursively, excluding known pivots.
+ */
+ if (parallel && length > PARALLEL_QUICKSORT_THRESHOLD) {
+ ForkJoinTask.invokeAll(
+ new Sorter(a, bits | 1, lower + 1, upper),
+ new Sorter(a, bits | 1, upper + 1, high),
+ new Sorter(a, bits, low, lower)
+ );
+ } else {
+ sort(a, bits | 1, false, upper + 1, high);
+ sort(a, bits, false, low, lower);
+ sort(a, bits | 1, false, lower + 1, upper);
+ }
} else { // Partitioning with one pivot
+
/*
- * Use the third of the five sorted elements as pivot.
- * This value is inexpensive approximation of the median.
+ * Use the third element as the pivot. This value
+ * is inexpensive approximation of the median.
*/
float pivot = a[e3];
/*
- * Partitioning degenerates to the traditional 3-way
- * (or "Dutch National Flag") schema:
- *
- * left part center part right part
- * +-------------------------------------------------+
- * | < pivot | == pivot | ? | > pivot |
- * +-------------------------------------------------+
- * ^ ^ ^
- * | | |
- * less k great
+ * The first element to be sorted is moved to the location
+ * formerly occupied by the pivot. When partitioning is
+ * completed, the pivot is swapped back into its final
+ * position, and excluded from subsequent sorting.
+ */
+ a[e3] = a[lower];
+
+ /*
+ * Traditional 3-way (Dutch National Flag) partitioning
+ *
+ * left part central part right part
+ * +------------------------------------------------------+
+ * | < pivot | ? | == pivot | > pivot |
+ * +------------------------------------------------------+
+ * ^ ^ ^
+ * | | |
+ * lower k upper
*
* Invariants:
*
- * all in (left, less) < pivot
- * all in [less, k) == pivot
- * all in (great, right) > pivot
+ * all in (low, lower] < pivot
+ * all in (k, upper) == pivot
+ * all in [upper, end] > pivot
*
- * Pointer k is the first index of ?-part.
+ * Pointer k is the last index of ?-part
*/
- for (int k = less; k <= great; ++k) {
+ for (int k = ++upper; --k > lower; ) {
if (a[k] == pivot) {
continue;
}
float ak = a[k];
- if (ak < pivot) { // Move a[k] to left part
- a[k] = a[less];
- a[less] = ak;
- ++less;
- } else { // a[k] > pivot - Move a[k] to right part
- while (a[great] > pivot) {
- --great;
- }
- if (a[great] < pivot) { // a[great] <= pivot
- a[k] = a[less];
- a[less] = a[great];
- ++less;
- } else { // a[great] == pivot
- /*
- * Even though a[great] equals to pivot, the
- * assignment a[k] = pivot may be incorrect,
- * if a[great] and pivot 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] = a[great];
+
+ if (ak < pivot) { // Move a[k] to the left side
+ while (a[++lower] < pivot);
+
+ if (lower > k) {
+ lower = k;
+ break;
}
- a[great] = ak;
- --great;
+ a[k] = pivot;
+
+ if (a[lower] > pivot) {
+ a[--upper] = a[lower];
+ }
+ a[lower] = ak;
+ } else { // ak > pivot - Move a[k] to the right side
+ a[k] = pivot;
+ a[--upper] = ak;
}
}
/*
- * Sort left and right parts recursively.
- * All elements from center part are equal
+ * Swap the pivot into its final position.
+ */
+ a[low] = a[lower]; a[lower] = pivot;
+
+ /*
+ * Sort the left and the right parts recursively, excluding
+ * known pivot. All elements from the central part are equal
* and, therefore, already sorted.
*/
- sort(a, left, less - 1, leftmost);
- sort(a, great + 1, right, false);
+ if (parallel && length > PARALLEL_QUICKSORT_THRESHOLD) {
+ ForkJoinTask.invokeAll(
+ new Sorter(a, bits, low, lower),
+ new Sorter(a, bits | 1, upper, high)
+ );
+ } else {
+ sort(a, bits | 1, false, upper, high);
+ sort(a, bits, false, low, lower);
+ }
}
}
/**
- * Sorts the specified range of the array using the given
- * workspace array slice if possible for merging
+ * Sorts the specified range of the array.
*
* @param a the array to be sorted
- * @param left the index of the first element, inclusive, to be sorted
- * @param right the index of the last element, inclusive, to be sorted
- * @param work a workspace array (slice)
- * @param workBase origin of usable space in work array
- * @param workLen usable size of work array
+ * @param parallel indicates whether sorting is performed in parallel
+ * @param low the index of the first element, inclusive, to be sorted
+ * @param high the index of the last element, exclusive, to be sorted
*/
- static void sort(double[] a, int left, int right,
- double[] work, int workBase, int workLen) {
+ static void sort(double[] a, boolean parallel, int low, int high) {
/*
- * Phase 1: Move NaNs to the end of the array.
+ * Phase 1. Count the number of negative zero -0.0d,
+ * turn them into positive zero, and move all NaNs
+ * to the end of the array.
*/
- while (left <= right && Double.isNaN(a[right])) {
- --right;
- }
- for (int k = right; --k >= left; ) {
- double ak = a[k];
- if (ak != ak) { // a[k] is NaN
- a[k] = a[right];
- a[right] = ak;
- --right;
+ int numNegativeZero = 0;
+
+ for (int k = high; k > low; ) {
+ double ak = a[--k];
+
+ if (ak == 0.0d && Double.doubleToRawLongBits(ak) < 0) { // ak is -0.0d
+ numNegativeZero += 1;
+ a[k] = 0.0d;
+ } else if (ak != ak) { // ak is NaN
+ a[k] = a[--high];
+ a[high] = ak;
}
}
/*
- * Phase 2: Sort everything except NaNs (which are already in place).
+ * Phase 2. Sort everything except NaNs,
+ * which are already in place.
*/
- doSort(a, left, right, work, workBase, workLen);
+ sort(a, LEFTMOST_BITS, parallel, low, high);
/*
- * Phase 3: Place negative zeros before positive zeros.
+ * Phase 3. Turn positive zero 0.0d
+ * back into negative zero -0.0d.
*/
- int hi = right;
+ if (++numNegativeZero == 1) {
+ return;
+ }
/*
- * Find the first zero, or first positive, or last negative element.
+ * Find the position one less than
+ * the index of the first zero.
*/
- while (left < hi) {
- int middle = (left + hi) >>> 1;
- double middleValue = a[middle];
+ while (low <= high) {
+ int middle = (low + high) >>> 1;
- if (middleValue < 0.0d) {
- left = middle + 1;
+ if (a[middle] < 0) {
+ low = middle + 1;
} else {
- hi = middle;
+ high = middle - 1;
}
}
/*
- * Skip the last negative value (if any) or all leading negative zeros.
- */
- while (left <= right && Double.doubleToRawLongBits(a[left]) < 0) {
- ++left;
- }
-
- /*
- * Move negative zeros to the beginning of the sub-range.
- *
- * Partitioning:
- *
- * +----------------------------------------------------+
- * | < 0.0 | -0.0 | 0.0 | ? ( >= 0.0 ) |
- * +----------------------------------------------------+
- * ^ ^ ^
- * | | |
- * left p k
- *
- * Invariants:
- *
- * all in (*, left) < 0.0
- * all in [left, p) == -0.0
- * all in [p, k) == 0.0
- * all in [k, right] >= 0.0
- *
- * Pointer k is the first index of ?-part.
+ * Replace the required number of 0.0d by -0.0d.
*/
- 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;
- }
+ while (--numNegativeZero > 0) {
+ a[++high] = -0.0d;
}
}
/**
- * Sorts the specified range of the array.
+ * Sorts the specified range of the array by the 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 work a workspace array (slice)
- * @param workBase origin of usable space in work array
- * @param workLen usable size of work array
- */
- private static void doSort(double[] a, int left, int right,
- double[] work, int workBase, int workLen) {
- // Use Quicksort on small arrays
- if (right - left < QUICKSORT_THRESHOLD) {
- sort(a, left, right, true);
- return;
- }
+ * @param bits the recursion depth of Quicksort and the leftmost flag
+ * @param parallel indicates whether sorting is performed in parallel
+ * @param low the index of the first element, inclusive, to be sorted
+ * @param high the index of the last element, exclusive, to be sorted
+ */
+ private static void sort(double[] a, int bits, boolean parallel, int low, int high) {
+ int end = high - 1, length = high - low;
/*
- * Index run[i] is the start of i-th run
- * (ascending or descending sequence).
+ * Run insertion sorts on non-leftmost part.
*/
- int[] run = new int[MAX_RUN_COUNT + 1];
- int count = 0; run[0] = left;
-
- // Check if the array is nearly sorted
- for (int k = left; k < right; run[count] = k) {
- // Equal items in the beginning of the sequence
- while (k < right && a[k] == a[k + 1])
- k++;
- if (k == right) break; // Sequence finishes with equal items
- if (a[k] < a[k + 1]) { // ascending
- while (++k <= right && a[k - 1] <= a[k]);
- } else if (a[k] > a[k + 1]) { // descending
- while (++k <= right && a[k - 1] >= a[k]);
- // Transform into an ascending sequence
- for (int lo = run[count] - 1, hi = k; ++lo < --hi; ) {
- double t = a[lo]; a[lo] = a[hi]; a[hi] = t;
- }
- }
+ if ((bits & 1) > 0) {
- // Merge a transformed descending sequence followed by an
- // ascending sequence
- if (run[count] > left && a[run[count]] >= a[run[count] - 1]) {
- count--;
+ /*
+ * Use nano insertion sort on tiny part.
+ */
+ if (length < NANO_INSERTION_SORT_THRESHOLD) {
+ SortingAlgorithms.nanoInsertionSort(a, low, high);
+ return;
}
/*
- * The array is not highly structured,
- * use Quicksort instead of merge sort.
+ * Use pair insertion sort on small part.
*/
- if (++count == MAX_RUN_COUNT) {
- sort(a, left, right, true);
+ if (length < PAIR_INSERTION_SORT_THRESHOLD) {
+ SortingAlgorithms.pairInsertionSort(a, low, end);
return;
}
}
- // These invariants should hold true:
- // run[0] = 0
- // run[] = right + 1; (terminator)
-
- if (count == 0) {
- // A single equal run
- return;
- } else if (count == 1 && run[count] > right) {
- // Either a single ascending or a transformed descending run.
- // Always check that a final run is a proper terminator, otherwise
- // we have an unterminated trailing run, to handle downstream.
+ /*
+ * Switch to heap sort on the leftmost part or
+ * if the execution time is becoming quadratic.
+ */
+ if (length < HEAP_SORT_THRESHOLD || (bits -= 2) < 0) {
+ SortingAlgorithms.heapSort(a, low, end);
return;
}
- right++;
- if (run[count] < right) {
- // Corner case: the final run is not a terminator. This may happen
- // if a final run is an equals run, or there is a single-element run
- // at the end. Fix up by adding a proper terminator at the end.
- // Note that we terminate with (right + 1), incremented earlier.
- run[++count] = right;
- }
-
- // Determine alternation base for merge
- byte odd = 0;
- for (int n = 1; (n <<= 1) < count; odd ^= 1);
-
- // Use or create temporary array b for merging
- double[] b; // temp array; alternates with a
- int ao, bo; // array offsets from 'left'
- int blen = right - left; // space needed for b
- if (work == null || workLen < blen || workBase + blen > work.length) {
- work = new double[blen];
- workBase = 0;
- }
- if (odd == 0) {
- System.arraycopy(a, left, work, workBase, blen);
- b = a;
- bo = 0;
- a = work;
- ao = workBase - left;
- } else {
- b = work;
- ao = 0;
- bo = workBase - left;
- }
-
- // Merging
- for (int last; count > 1; count = last) {
- for (int k = (last = 0) + 2; k <= count; k += 2) {
- int hi = run[k], mi = run[k - 1];
- for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) {
- if (q >= hi || p < mi && a[p + ao] <= a[q + ao]) {
- b[i + bo] = a[p++ + ao];
- } else {
- b[i + bo] = a[q++ + ao];
- }
- }
- run[++last] = hi;
- }
- if ((count & 1) != 0) {
- for (int i = right, lo = run[count - 1]; --i >= lo;
- b[i + bo] = a[i + ao]
- );
- run[++last] = right;
- }
- double[] t = a; a = b; b = t;
- int o = ao; ao = bo; bo = o;
- }
- }
-
- /**
- * Sorts the specified range of the array by Dual-Pivot Quicksort.
- *
- * @param a the array to be sorted
- * @param left the index of the first element, inclusive, to be sorted
- * @param right the index of the last element, inclusive, to be sorted
- * @param leftmost indicates if this part is the leftmost in the range
- */
- private static void sort(double[] 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) {
- /*
- * 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];
- while (ai < a[j]) {
- a[j + 1] = a[j];
- if (j-- == left) {
- break;
- }
- }
- a[j + 1] = ai;
- }
- } else {
- /*
- * Skip the longest ascending sequence.
- */
- do {
- if (left >= right) {
- return;
- }
- } while (a[++left] >= a[left - 1]);
-
- /*
- * 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 more optimized algorithm, so called pair insertion
- * sort, which is faster (in the context of Quicksort)
- * than traditional implementation of insertion sort.
- */
- for (int k = left; ++left <= right; k = ++left) {
- double a1 = a[k], a2 = a[left];
-
- if (a1 < a2) {
- a2 = a1; a1 = 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;
- }
+ /*
+ * Check if the array is nearly sorted
+ * and then try to sort it by Merging sort.
+ */
+ if (SortingAlgorithms.mergingSort(a, parallel, low, high)) {
return;
}
- // Inexpensive approximation of length / 7
- int seventh = (length >> 3) + (length >> 6) + 1;
+ /*
+ * The splitting of the array, defined by the following
+ * step, is related to the inexpensive approximation of
+ * the golden ratio.
+ */
+ int step = (length >> 3) * 3 + 3;
/*
- * 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.
+ * Five elements around (and including) the central element in
+ * the array will be used for pivot selection as described below.
+ * The unequal choice of 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;
+ int e1 = low + step;
+ int e5 = end - step;
+ int e3 = (e1 + e5) >>> 1;
+ int e2 = (e1 + e3) >>> 1;
+ int e4 = (e3 + e5) >>> 1;
- // Sort these elements using insertion sort
- if (a[e2] < a[e1]) { double t = a[e2]; a[e2] = a[e1]; a[e1] = t; }
+ /*
+ * Sort these elements in place by the combination
+ * of 5-element sorting network and insertion sort.
+ */
+ if (a[e5] < a[e3]) { double t = a[e5]; a[e5] = a[e3]; a[e3] = t; }
+ if (a[e4] < a[e2]) { double t = a[e4]; a[e4] = a[e2]; a[e2] = t; }
+ if (a[e5] < a[e4]) { double t = a[e5]; a[e5] = a[e4]; a[e4] = t; }
+ if (a[e3] < a[e2]) { double t = a[e3]; a[e3] = a[e2]; a[e2] = t; }
+ if (a[e4] < a[e3]) { double t = a[e4]; a[e4] = a[e3]; a[e3] = t; }
- if (a[e3] < a[e2]) { double 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]) { double 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]) { double 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; }
+ if (a[e1] > a[e2]) { double t = a[e1]; a[e1] = a[e2]; a[e2] = t;
+ if (t > a[e3]) { a[e2] = a[e3]; a[e3] = t;
+ if (t > a[e4]) { a[e3] = a[e4]; a[e4] = t;
+ if (t > a[e5]) { a[e4] = a[e5]; a[e5] = t; }
}
}
}
// 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
+ int lower = low; // The index of the last element of the left part
+ int upper = end; // The index of the first element of the right part
+
+ if (a[e1] < a[e2] && a[e2] < a[e3] && a[e3] < a[e4] && a[e4] < a[e5]) {
- if (a[e1] != a[e2] && a[e2] != a[e3] && a[e3] != a[e4] && a[e4] != a[e5]) {
/*
- * Use the second and fourth of the five sorted elements as pivots.
- * These values are inexpensive approximations of the first and
- * second terciles of the array. Note that pivot1 <= pivot2.
+ * Use the first and the fifth elements as the pivots.
+ * These values are inexpensive approximation of tertiles.
+ * Note, that pivot1 < pivot2.
*/
- double pivot1 = a[e2];
- double pivot2 = a[e4];
+ double pivot1 = a[e1];
+ double pivot2 = a[e5];
/*
* 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
+ * is completed, the pivots are swapped back into their final
* positions, and excluded from subsequent sorting.
*/
- a[e2] = a[left];
- a[e4] = a[right];
+ a[e1] = a[lower];
+ a[e5] = a[upper];
/*
- * Skip elements, which are less or greater than pivot values.
+ * Skip elements, which are less or greater than the pivots.
*/
- while (a[++less] < pivot1);
- while (a[--great] > pivot2);
+ while (a[++lower] < pivot1);
+ while (a[--upper] > pivot2);
/*
- * Partitioning:
+ * Backwards 3-interval partitioning
*
- * left part center part right part
- * +--------------------------------------------------------------+
- * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 |
- * +--------------------------------------------------------------+
- * ^ ^ ^
- * | | |
- * less k great
+ * left part central part right part
+ * +------------------------------------------------------------+
+ * | < pivot1 | ? | pivot1 <= && <= pivot2 | > pivot2 |
+ * +------------------------------------------------------------+
+ * ^ ^ ^
+ * | | |
+ * lower k upper
*
* Invariants:
*
- * all in (left, less) < pivot1
- * pivot1 <= all in [less, k) <= pivot2
- * all in (great, right) > pivot2
+ * all in (low, lower] < pivot1
+ * pivot1 <= all in (k, upper) <= pivot2
+ * all in [upper, end) > pivot2
*
- * Pointer k is the first index of ?-part.
+ * Pointer k is the last index of ?-part
*/
- outer:
- for (int k = less - 1; ++k <= great; ) {
+ for (int $ = --lower, k = ++upper; --k > lower; ) {
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
- while (a[great] > pivot2) {
- if (great-- == k) {
- break outer;
- }
- }
- 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;
- }
- }
-
- // 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 > 4/7 of the array),
- * swap internal pivot values to ends.
- */
- if (less < e1 && e5 < great) {
- /*
- * Skip elements, which are equal to pivot values.
- */
- while (a[less] == pivot1) {
- ++less;
- }
-
- while (a[great] == pivot2) {
- --great;
- }
-
- /*
- * Partitioning:
- *
- * left part center part right part
- * +----------------------------------------------------------+
- * | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 |
- * +----------------------------------------------------------+
- * ^ ^ ^
- * | | |
- * less k great
- *
- * Invariants:
- *
- * all in (*, less) == pivot1
- * pivot1 < all in [less, k) < pivot2
- * all in (great, *) == pivot2
- *
- * Pointer k is the first index of ?-part.
- */
- outer:
- for (int k = less - 1; ++k <= great; ) {
- double 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[great] < pivot2
- 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] = a[great];
- ++less;
- } else { // pivot1 < a[great] < pivot2
- a[k] = a[great];
- }
- a[great] = ak;
- --great;
+
+ if (ak < pivot1) { // Move a[k] to the left side
+ while (a[++lower] < pivot1);
+
+ if (lower > k) {
+ lower = k;
+ break;
+ }
+ if (a[lower] > pivot2) { // a[lower] >= pivot1
+ a[k] = a[--upper];
+ a[upper] = a[lower];
+ } else { // pivot1 <= a[lower] <= pivot2
+ a[k] = a[lower];
}
+ a[lower] = ak;
+ } else if (ak > pivot2) { // Move a[k] to the right side
+ a[k] = a[--upper];
+ a[upper] = ak;
}
}
- // Sort center part recursively
- sort(a, less, great, false);
+ /*
+ * Swap the pivots into their final positions.
+ */
+ a[low] = a[lower]; a[lower] = pivot1;
+ a[end] = a[upper]; a[upper] = pivot2;
+ /*
+ * Sort all parts recursively, excluding known pivots.
+ */
+ if (parallel && length > PARALLEL_QUICKSORT_THRESHOLD) {
+ ForkJoinTask.invokeAll(
+ new Sorter(a, bits | 1, lower + 1, upper),
+ new Sorter(a, bits | 1, upper + 1, high),
+ new Sorter(a, bits, low, lower)
+ );
+ } else {
+ sort(a, bits | 1, false, upper + 1, high);
+ sort(a, bits, false, low, lower);
+ sort(a, bits | 1, false, lower + 1, upper);
+ }
} else { // Partitioning with one pivot
+
/*
- * Use the third of the five sorted elements as pivot.
- * This value is inexpensive approximation of the median.
+ * Use the third element as the pivot. This value
+ * is inexpensive approximation of the median.
*/
double pivot = a[e3];
/*
- * Partitioning degenerates to the traditional 3-way
- * (or "Dutch National Flag") schema:
- *
- * left part center part right part
- * +-------------------------------------------------+
- * | < pivot | == pivot | ? | > pivot |
- * +-------------------------------------------------+
- * ^ ^ ^
- * | | |
- * less k great
+ * The first element to be sorted is moved to the location
+ * formerly occupied by the pivot. When partitioning is
+ * completed, the pivot is swapped back into its final
+ * position, and excluded from subsequent sorting.
+ */
+ a[e3] = a[lower];
+
+ /*
+ * Traditional 3-way (Dutch National Flag) partitioning
+ *
+ * left part central part right part
+ * +------------------------------------------------------+
+ * | < pivot | ? | == pivot | > pivot |
+ * +------------------------------------------------------+
+ * ^ ^ ^
+ * | | |
+ * lower k upper
*
* Invariants:
*
- * all in (left, less) < pivot
- * all in [less, k) == pivot
- * all in (great, right) > pivot
+ * all in (low, lower] < pivot
+ * all in (k, upper) == pivot
+ * all in [upper, end] > pivot
*
- * Pointer k is the first index of ?-part.
+ * Pointer k is the last index of ?-part
*/
- for (int k = less; k <= great; ++k) {
+ for (int k = ++upper; --k > lower; ) {
if (a[k] == pivot) {
continue;
}
double ak = a[k];
- if (ak < pivot) { // Move a[k] to left part
- a[k] = a[less];
- a[less] = ak;
- ++less;
- } else { // a[k] > pivot - Move a[k] to right part
- while (a[great] > pivot) {
- --great;
- }
- if (a[great] < pivot) { // a[great] <= pivot
- a[k] = a[less];
- a[less] = a[great];
- ++less;
- } else { // a[great] == pivot
- /*
- * Even though a[great] equals to pivot, the
- * assignment a[k] = pivot may be incorrect,
- * if a[great] and pivot 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] = a[great];
+
+ if (ak < pivot) { // Move a[k] to the left side
+ while (a[++lower] < pivot);
+
+ if (lower > k) {
+ lower = k;
+ break;
}
- a[great] = ak;
- --great;
+ a[k] = pivot;
+
+ if (a[lower] > pivot) {
+ a[--upper] = a[lower];
+ }
+ a[lower] = ak;
+ } else { // ak > pivot - Move a[k] to the right side
+ a[k] = pivot;
+ a[--upper] = ak;
}
}
/*
- * Sort left and right parts recursively.
- * All elements from center part are equal
+ * Swap the pivot into its final position.
+ */
+ a[low] = a[lower]; a[lower] = pivot;
+
+ /*
+ * Sort the left and the right parts recursively, excluding
+ * known pivot. All elements from the central part are equal
* and, therefore, already sorted.
*/
- sort(a, left, less - 1, leftmost);
- sort(a, great + 1, right, false);
+ if (parallel && length > PARALLEL_QUICKSORT_THRESHOLD) {
+ ForkJoinTask.invokeAll(
+ new Sorter(a, bits, low, lower),
+ new Sorter(a, bits | 1, upper, high)
+ );
+ } else {
+ sort(a, bits | 1, false, upper, high);
+ sort(a, bits, false, low, lower);
+ }
}
}
}
--- old/test/jdk/java/util/Arrays/ParallelSorting.java 2018-01-18 06:09:11.474015532 -0800
+++ new/test/jdk/java/util/Arrays/ParallelSorting.java 2018-01-18 06:09:11.077978781 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,38 +23,41 @@
/* Adapted from test/java/util/Arrays/Sorting.java
*
+ * To generate the source of this class, take the source of Sorting.java
+ * and replace "Arrays.sort' by "Arrays.parallelSort'.
+ *
* Where that test checks Arrays.sort against manual quicksort routines,
- * this test checks parallelSort against either Arrays.sort or manual
- * quicksort routines.
+ * this test checks parallelSort against manual quicksort routines.
*/
/*
* @test
* @bug 8003981
* @run main ParallelSorting -shortrun
- * @summary Exercise Arrays.parallelSort (adapted from test Sorting)
+ * @summary Exercise Arrays.parallelSort
*
* @author Vladimir Yaroslavskiy
* @author Jon Bentley
* @author Josh Bloch
*/
+import java.io.PrintStream;
import java.util.Arrays;
import java.util.Random;
-import java.io.PrintStream;
import java.util.Comparator;
public class ParallelSorting {
+
private static final PrintStream out = System.out;
private static final PrintStream err = System.err;
// Array lengths used in a long run (default)
private static final int[] LONG_RUN_LENGTHS = {
- 1000, 10000, 100000, 1000000 };
+ 1, 2, 3, 5, 8, 13, 21, 34, 55, 100, 1000, 10000, 100000, 1000000 };
// Array lengths used in a short run
private static final int[] SHORT_RUN_LENGTHS = {
- 5000, 9000, 10000, 12000 };
+ 1, 2, 3, 21, 55, 1000, 10000, 12000 };
// Random initial values used in a long run (default)
private static final long[] LONG_RUN_RANDOMS = { 666, 0xC0FFEE, 999 };
@@ -62,6 +65,10 @@
// Random initial values used in a short run
private static final long[] SHORT_RUN_RANDOMS = { 666 };
+ // Constant values used in subarray sorting
+ private static final int A380 = 0xA380;
+ private static final int B747 = 0xB747;
+
public static void main(String[] args) {
boolean shortRun = args.length > 0 && args[0].equals("-shortrun");
long start = System.currentTimeMillis();
@@ -86,7 +93,7 @@
testEmptyAndNullDoubleArray();
for (int length : lengths) {
- testMergeSort(length);
+ testMergingSort(length);
testAndCheckRange(length);
testAndCheckSubArray(length);
}
@@ -104,8 +111,8 @@
private static void testEmptyAndNullIntArray() {
ourDescription = "Check empty and null array";
- Arrays.parallelSort(new int[]{});
- Arrays.parallelSort(new int[]{}, 0, 0);
+ Arrays.parallelSort(new int[] {});
+ Arrays.parallelSort(new int[] {}, 0, 0);
try {
Arrays.parallelSort((int[]) null);
@@ -123,8 +130,8 @@
private static void testEmptyAndNullLongArray() {
ourDescription = "Check empty and null array";
- Arrays.parallelSort(new long[]{});
- Arrays.parallelSort(new long[]{}, 0, 0);
+ Arrays.parallelSort(new long[] {});
+ Arrays.parallelSort(new long[] {}, 0, 0);
try {
Arrays.parallelSort((long[]) null);
@@ -142,8 +149,8 @@
private static void testEmptyAndNullShortArray() {
ourDescription = "Check empty and null array";
- Arrays.parallelSort(new short[]{});
- Arrays.parallelSort(new short[]{}, 0, 0);
+ Arrays.parallelSort(new short[] {});
+ Arrays.parallelSort(new short[] {}, 0, 0);
try {
Arrays.parallelSort((short[]) null);
@@ -161,8 +168,8 @@
private static void testEmptyAndNullCharArray() {
ourDescription = "Check empty and null array";
- Arrays.parallelSort(new char[]{});
- Arrays.parallelSort(new char[]{}, 0, 0);
+ Arrays.parallelSort(new char[] {});
+ Arrays.parallelSort(new char[] {}, 0, 0);
try {
Arrays.parallelSort((char[]) null);
@@ -180,8 +187,8 @@
private static void testEmptyAndNullByteArray() {
ourDescription = "Check empty and null array";
- Arrays.parallelSort(new byte[]{});
- Arrays.parallelSort(new byte[]{}, 0, 0);
+ Arrays.parallelSort(new byte[] {});
+ Arrays.parallelSort(new byte[] {}, 0, 0);
try {
Arrays.parallelSort((byte[]) null);
@@ -199,8 +206,8 @@
private static void testEmptyAndNullFloatArray() {
ourDescription = "Check empty and null array";
- Arrays.parallelSort(new float[]{});
- Arrays.parallelSort(new float[]{}, 0, 0);
+ Arrays.parallelSort(new float[] {});
+ Arrays.parallelSort(new float[] {}, 0, 0);
try {
Arrays.parallelSort((float[]) null);
@@ -218,8 +225,8 @@
private static void testEmptyAndNullDoubleArray() {
ourDescription = "Check empty and null array";
- Arrays.parallelSort(new double[]{});
- Arrays.parallelSort(new double[]{}, 0, 0);
+ Arrays.parallelSort(new double[] {});
+ Arrays.parallelSort(new double[] {}, 0, 0);
try {
Arrays.parallelSort((double[]) null);
@@ -295,11 +302,10 @@
out.println("Test 'stable' comparator: " + "random = " + random.getSeed() +
", length = " + length);
- Arrays.parallelSort(a, pairCmp);
+ Arrays.parallelSort(a, pairComparator);
checkSorted(a);
checkStable(a);
out.println();
-
}
private static void checkSorted(Pair[] a) {
@@ -346,7 +352,7 @@
return a;
}
- private static Comparator pairCmp = new Comparator() {
+ private static Comparator pairComparator = new Comparator() {
public int compare(Pair p1, Pair p2) {
return p1.compareTo(p2);
}
@@ -414,21 +420,21 @@
out.println();
}
- private static void testMergeSort(int length) {
+ private static void testMergingSort(int length) {
if (length < 1000) {
return;
}
- ourDescription = "Check merge sorting";
+ ourDescription = "Check merging sort";
int[] golden = new int[length];
- int period = 67; // java.util.DualPivotQuicksort.MAX_RUN_COUNT
+ final int period = 50;
for (int m = period - 2; m <= period + 2; m++) {
- for (MergeBuilder builder : MergeBuilder.values()) {
+ for (MergingBuilder builder : MergingBuilder.values()) {
builder.build(golden, m);
int[] test = golden.clone();
for (TypeConverter converter : TypeConverter.values()) {
- out.println("Test 'merge sort': " + converter + " " +
+ out.println("Test 'merging sort': " + converter + " " +
builder + "length = " + length + ", m = " + m);
Object convertedGolden = converter.convert(golden);
sort(convertedGolden);
@@ -492,18 +498,15 @@
private static void testAndCheckFloat(int length, MyRandom random) {
ourDescription = "Check float sorting";
float[] golden = new float[length];
- final int MAX = 10;
boolean newLine = false;
+ final int MAX = 12;
for (int a = 0; a <= MAX; a++) {
for (int g = 0; g <= MAX; g++) {
for (int z = 0; z <= MAX; z++) {
for (int n = 0; n <= MAX; n++) {
for (int p = 0; p <= MAX; p++) {
- if (a + g + z + n + p > length) {
- continue;
- }
- if (a + g + z + n + p < length) {
+ if (a + g + z + n + p != length) {
continue;
}
for (FloatBuilder builder : FloatBuilder.values()) {
@@ -567,7 +570,7 @@
private static void prepareSubArray(int[] a, int fromIndex, int toIndex, int m) {
for (int i = 0; i < fromIndex; i++) {
- a[i] = 0xDEDA;
+ a[i] = A380;
}
int middle = (fromIndex + toIndex) >>> 1;
int k = 0;
@@ -579,7 +582,7 @@
a[i] = k--;
}
for (int i = toIndex; i < a.length; i++) {
- a[i] = 0xBABA;
+ a[i] = B747;
}
}
@@ -690,7 +693,7 @@
Integer[] b = new Integer[a.length];
for (int i = 0; i < a.length; i++) {
- b[i] = new Integer(a[i]);
+ b[i] = Integer.valueOf(a[i]);
}
return b;
}
@@ -698,7 +701,8 @@
abstract Object convert(int[] a);
- @Override public String toString() {
+ @Override
+ public String toString() {
String name = name();
for (int i = name.length(); i < 9; i++) {
@@ -851,7 +855,8 @@
abstract void build(int[] a, int m);
- @Override public String toString() {
+ @Override
+ public String toString() {
String name = name();
for (int i = name.length(); i < 12; i++) {
@@ -861,7 +866,7 @@
}
}
- private static enum MergeBuilder {
+ private static enum MergingBuilder {
ASCENDING {
void build(int[] a, int m) {
int period = a.length / m;
@@ -895,11 +900,53 @@
}
a[a.length - 1] = 0;
}
+ },
+ POINT {
+ void build(int[] a, int m) {
+ for (int i = 0; i < a.length; i++) {
+ a[i] = 0;
+ }
+ a[a.length / 2] = m;
+ }
+ },
+ LINE {
+ void build(int[] a, int m) {
+ for (int i = 0; i < a.length; i++) {
+ a[i] = i;
+ }
+ reverse(a, 0, a.length - 1);
+ }
+ },
+ PEARL {
+ void build(int[] a, int m) {
+ for (int i = 0; i < a.length; i++) {
+ a[i] = i;
+ }
+ reverse(a, 0, 2);
+ }
+ },
+ RING {
+ void build(int[] a, int m) {
+ int k1 = a.length / 3;
+ int k2 = a.length / 3 * 2;
+ int level = a.length / 3;
+
+ for (int i = 0, k = level; i < k1; i++) {
+ a[i] = k--;
+ }
+ for (int i = k1; i < k2; i++) {
+ a[i] = 0;
+ }
+ for (int i = k2, k = level; i < a.length; i++) {
+ a[i] = k--;
+ }
+ }
};
abstract void build(int[] a, int m);
- @Override public String toString() {
+ @Override
+ public String toString() {
String name = name();
for (int i = name.length(); i < 12; i++) {
@@ -909,6 +956,14 @@
}
}
+ private static void reverse(int[] a, int lo, int hi) {
+ for (--hi; lo < hi; ) {
+ int tmp = a[lo];
+ a[lo++] = a[hi];
+ a[hi--] = tmp;
+ }
+ }
+
private static enum UnsortedBuilder {
RANDOM {
void build(int[] a, int m, Random random) {
@@ -1015,7 +1070,8 @@
abstract void build(int[] a, int m, Random random);
- @Override public String toString() {
+ @Override
+ public String toString() {
String name = name();
for (int i = name.length(); i < 12; i++) {
@@ -1062,7 +1118,7 @@
} else if (test instanceof Integer[]) {
compare((Integer[]) test, (Integer[]) golden);
} else {
- failed("Unknow type of array: " + test + " of class " +
+ failed("Unknown type of array: " + test + " of class " +
test.getClass().getName());
}
}
@@ -1149,7 +1205,7 @@
} else if (object instanceof Integer[]) {
checkSorted((Integer[]) object);
} else {
- failed("Unknow type of array: " + object + " of class " +
+ failed("Unknown type of array: " + object + " of class " +
object.getClass().getName());
}
}
@@ -1245,7 +1301,7 @@
} else if (object instanceof Integer[]) {
return checkSumXor((Integer[]) object);
} else {
- failed("Unknow type of array: " + object + " of class " +
+ failed("Unknown type of array: " + object + " of class " +
object.getClass().getName());
return -1;
}
@@ -1341,7 +1397,7 @@
} else if (object instanceof Integer[]) {
return checkSumPlus((Integer[]) object);
} else {
- failed("Unknow type of array: " + object + " of class " +
+ failed("Unknown type of array: " + object + " of class " +
object.getClass().getName());
return -1;
}
@@ -1437,7 +1493,7 @@
} else if (object instanceof Integer[]) {
sortByInsertionSort((Integer[]) object);
} else {
- failed("Unknow type of array: " + object + " of class " +
+ failed("Unknown type of array: " + object + " of class " +
object.getClass().getName());
}
}
@@ -1540,7 +1596,7 @@
} else if (object instanceof Integer[]) {
Arrays.parallelSort((Integer[]) object);
} else {
- failed("Unknow type of array: " + object + " of class " +
+ failed("Unknown type of array: " + object + " of class " +
object.getClass().getName());
}
}
@@ -1563,7 +1619,7 @@
} else if (object instanceof Integer[]) {
Arrays.parallelSort((Integer[]) object, fromIndex, toIndex);
} else {
- failed("Unknow type of array: " + object + " of class " +
+ failed("Unknown type of array: " + object + " of class " +
object.getClass().getName());
}
}
@@ -1586,16 +1642,16 @@
} else if (object instanceof Integer[]) {
checkSubArray((Integer[]) object, fromIndex, toIndex, m);
} else {
- failed("Unknow type of array: " + object + " of class " +
+ failed("Unknown type of array: " + object + " of class " +
object.getClass().getName());
}
}
private static void checkSubArray(Integer[] a, int fromIndex, int toIndex, int m) {
for (int i = 0; i < fromIndex; i++) {
- if (a[i].intValue() != 0xDEDA) {
+ if (a[i].intValue() != A380) {
failed("Range sort changes left element on position " + i +
- ": " + a[i] + ", must be " + 0xDEDA);
+ ": " + a[i] + ", must be " + A380);
}
}
@@ -1606,18 +1662,18 @@
}
for (int i = toIndex; i < a.length; i++) {
- if (a[i].intValue() != 0xBABA) {
+ if (a[i].intValue() != B747) {
failed("Range sort changes right element on position " + i +
- ": " + a[i] + ", must be " + 0xBABA);
+ ": " + a[i] + ", must be " + B747);
}
}
}
private static void checkSubArray(int[] a, int fromIndex, int toIndex, int m) {
for (int i = 0; i < fromIndex; i++) {
- if (a[i] != 0xDEDA) {
+ if (a[i] != A380) {
failed("Range sort changes left element on position " + i +
- ": " + a[i] + ", must be " + 0xDEDA);
+ ": " + a[i] + ", must be " + A380);
}
}
@@ -1628,18 +1684,18 @@
}
for (int i = toIndex; i < a.length; i++) {
- if (a[i] != 0xBABA) {
+ if (a[i] != B747) {
failed("Range sort changes right element on position " + i +
- ": " + a[i] + ", must be " + 0xBABA);
+ ": " + a[i] + ", must be " + B747);
}
}
}
private static void checkSubArray(byte[] a, int fromIndex, int toIndex, int m) {
for (int i = 0; i < fromIndex; i++) {
- if (a[i] != (byte) 0xDEDA) {
+ if (a[i] != (byte) A380) {
failed("Range sort changes left element on position " + i +
- ": " + a[i] + ", must be " + 0xDEDA);
+ ": " + a[i] + ", must be " + A380);
}
}
@@ -1650,18 +1706,18 @@
}
for (int i = toIndex; i < a.length; i++) {
- if (a[i] != (byte) 0xBABA) {
+ if (a[i] != (byte) B747) {
failed("Range sort changes right element on position " + i +
- ": " + a[i] + ", must be " + 0xBABA);
+ ": " + a[i] + ", must be " + B747);
}
}
}
private static void checkSubArray(long[] a, int fromIndex, int toIndex, int m) {
for (int i = 0; i < fromIndex; i++) {
- if (a[i] != (long) 0xDEDA) {
+ if (a[i] != (long) A380) {
failed("Range sort changes left element on position " + i +
- ": " + a[i] + ", must be " + 0xDEDA);
+ ": " + a[i] + ", must be " + A380);
}
}
@@ -1672,18 +1728,18 @@
}
for (int i = toIndex; i < a.length; i++) {
- if (a[i] != (long) 0xBABA) {
+ if (a[i] != (long) B747) {
failed("Range sort changes right element on position " + i +
- ": " + a[i] + ", must be " + 0xBABA);
+ ": " + a[i] + ", must be " + B747);
}
}
}
private static void checkSubArray(char[] a, int fromIndex, int toIndex, int m) {
for (int i = 0; i < fromIndex; i++) {
- if (a[i] != (char) 0xDEDA) {
+ if (a[i] != (char) A380) {
failed("Range sort changes left element on position " + i +
- ": " + a[i] + ", must be " + 0xDEDA);
+ ": " + a[i] + ", must be " + A380);
}
}
@@ -1694,18 +1750,18 @@
}
for (int i = toIndex; i < a.length; i++) {
- if (a[i] != (char) 0xBABA) {
+ if (a[i] != (char) B747) {
failed("Range sort changes right element on position " + i +
- ": " + a[i] + ", must be " + 0xBABA);
+ ": " + a[i] + ", must be " + B747);
}
}
}
private static void checkSubArray(short[] a, int fromIndex, int toIndex, int m) {
for (int i = 0; i < fromIndex; i++) {
- if (a[i] != (short) 0xDEDA) {
+ if (a[i] != (short) A380) {
failed("Range sort changes left element on position " + i +
- ": " + a[i] + ", must be " + 0xDEDA);
+ ": " + a[i] + ", must be " + A380);
}
}
@@ -1716,18 +1772,18 @@
}
for (int i = toIndex; i < a.length; i++) {
- if (a[i] != (short) 0xBABA) {
+ if (a[i] != (short) B747) {
failed("Range sort changes right element on position " + i +
- ": " + a[i] + ", must be " + 0xBABA);
+ ": " + a[i] + ", must be " + B747);
}
}
}
private static void checkSubArray(float[] a, int fromIndex, int toIndex, int m) {
for (int i = 0; i < fromIndex; i++) {
- if (a[i] != (float) 0xDEDA) {
+ if (a[i] != (float) A380) {
failed("Range sort changes left element on position " + i +
- ": " + a[i] + ", must be " + 0xDEDA);
+ ": " + a[i] + ", must be " + A380);
}
}
@@ -1738,18 +1794,18 @@
}
for (int i = toIndex; i < a.length; i++) {
- if (a[i] != (float) 0xBABA) {
+ if (a[i] != (float) B747) {
failed("Range sort changes right element on position " + i +
- ": " + a[i] + ", must be " + 0xBABA);
+ ": " + a[i] + ", must be " + B747);
}
}
}
private static void checkSubArray(double[] a, int fromIndex, int toIndex, int m) {
for (int i = 0; i < fromIndex; i++) {
- if (a[i] != (double) 0xDEDA) {
+ if (a[i] != (double) A380) {
failed("Range sort changes left element on position " + i +
- ": " + a[i] + ", must be " + 0xDEDA);
+ ": " + a[i] + ", must be " + A380);
}
}
@@ -1760,9 +1816,9 @@
}
for (int i = toIndex; i < a.length; i++) {
- if (a[i] != (double) 0xBABA) {
+ if (a[i] != (double) B747) {
failed("Range sort changes right element on position " + i +
- ": " + a[i] + ", must be " + 0xBABA);
+ ": " + a[i] + ", must be " + B747);
}
}
}
@@ -1785,7 +1841,7 @@
} else if (object instanceof Integer[]) {
checkRange((Integer[]) object, m);
} else {
- failed("Unknow type of array: " + object + " of class " +
+ failed("Unknown type of array: " + object + " of class " +
object.getClass().getName());
}
}
@@ -1794,7 +1850,7 @@
try {
Arrays.parallelSort(a, m + 1, m);
- failed("ParallelSort does not throw IllegalArgumentException " +
+ failed("Arrays.parallelSort does not throw IllegalArgumentException " +
" as expected: fromIndex = " + (m + 1) +
" toIndex = " + m);
}
@@ -1802,14 +1858,14 @@
try {
Arrays.parallelSort(a, -m, a.length);
- failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+ failed("Arrays.parallelSort does not throw ArrayIndexOutOfBoundsException " +
" as expected: fromIndex = " + (-m));
}
catch (ArrayIndexOutOfBoundsException aoe) {
try {
Arrays.parallelSort(a, 0, a.length + m);
- failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+ failed("Arrays.parallelSort does not throw ArrayIndexOutOfBoundsException " +
" as expected: toIndex = " + (a.length + m));
}
catch (ArrayIndexOutOfBoundsException aie) {
@@ -1823,7 +1879,7 @@
try {
Arrays.parallelSort(a, m + 1, m);
- failed("ParallelSort does not throw IllegalArgumentException " +
+ failed("Arrays.parallelSort does not throw IllegalArgumentException " +
" as expected: fromIndex = " + (m + 1) +
" toIndex = " + m);
}
@@ -1831,14 +1887,14 @@
try {
Arrays.parallelSort(a, -m, a.length);
- failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+ failed("Arrays.parallelSort does not throw ArrayIndexOutOfBoundsException " +
" as expected: fromIndex = " + (-m));
}
catch (ArrayIndexOutOfBoundsException aoe) {
try {
Arrays.parallelSort(a, 0, a.length + m);
- failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+ failed("Arrays.parallelSort does not throw ArrayIndexOutOfBoundsException " +
" as expected: toIndex = " + (a.length + m));
}
catch (ArrayIndexOutOfBoundsException aie) {
@@ -1852,7 +1908,7 @@
try {
Arrays.parallelSort(a, m + 1, m);
- failed("ParallelSort does not throw IllegalArgumentException " +
+ failed("Arrays.parallelSort does not throw IllegalArgumentException " +
" as expected: fromIndex = " + (m + 1) +
" toIndex = " + m);
}
@@ -1860,14 +1916,14 @@
try {
Arrays.parallelSort(a, -m, a.length);
- failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+ failed("Arrays.parallelSort does not throw ArrayIndexOutOfBoundsException " +
" as expected: fromIndex = " + (-m));
}
catch (ArrayIndexOutOfBoundsException aoe) {
try {
Arrays.parallelSort(a, 0, a.length + m);
- failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+ failed("Arrays.parallelSort does not throw ArrayIndexOutOfBoundsException " +
" as expected: toIndex = " + (a.length + m));
}
catch (ArrayIndexOutOfBoundsException aie) {
@@ -1881,7 +1937,7 @@
try {
Arrays.parallelSort(a, m + 1, m);
- failed("ParallelSort does not throw IllegalArgumentException " +
+ failed("Arrays.parallelSort does not throw IllegalArgumentException " +
" as expected: fromIndex = " + (m + 1) +
" toIndex = " + m);
}
@@ -1889,14 +1945,14 @@
try {
Arrays.parallelSort(a, -m, a.length);
- failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+ failed("Arrays.parallelSort does not throw ArrayIndexOutOfBoundsException " +
" as expected: fromIndex = " + (-m));
}
catch (ArrayIndexOutOfBoundsException aoe) {
try {
Arrays.parallelSort(a, 0, a.length + m);
- failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+ failed("Arrays.parallelSort does not throw ArrayIndexOutOfBoundsException " +
" as expected: toIndex = " + (a.length + m));
}
catch (ArrayIndexOutOfBoundsException aie) {
@@ -1910,7 +1966,7 @@
try {
Arrays.parallelSort(a, m + 1, m);
- failed("ParallelSort does not throw IllegalArgumentException " +
+ failed("Arrays.parallelSort does not throw IllegalArgumentException " +
" as expected: fromIndex = " + (m + 1) +
" toIndex = " + m);
}
@@ -1918,14 +1974,14 @@
try {
Arrays.parallelSort(a, -m, a.length);
- failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+ failed("Arrays.parallelSort does not throw ArrayIndexOutOfBoundsException " +
" as expected: fromIndex = " + (-m));
}
catch (ArrayIndexOutOfBoundsException aoe) {
try {
Arrays.parallelSort(a, 0, a.length + m);
- failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+ failed("Arrays.parallelSort does not throw ArrayIndexOutOfBoundsException " +
" as expected: toIndex = " + (a.length + m));
}
catch (ArrayIndexOutOfBoundsException aie) {
@@ -1939,7 +1995,7 @@
try {
Arrays.parallelSort(a, m + 1, m);
- failed("ParallelSort does not throw IllegalArgumentException " +
+ failed("Arrays.parallelSort does not throw IllegalArgumentException " +
" as expected: fromIndex = " + (m + 1) +
" toIndex = " + m);
}
@@ -1947,14 +2003,14 @@
try {
Arrays.parallelSort(a, -m, a.length);
- failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+ failed("Arrays.parallelSort does not throw ArrayIndexOutOfBoundsException " +
" as expected: fromIndex = " + (-m));
}
catch (ArrayIndexOutOfBoundsException aoe) {
try {
Arrays.parallelSort(a, 0, a.length + m);
- failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+ failed("Arrays.parallelSort does not throw ArrayIndexOutOfBoundsException " +
" as expected: toIndex = " + (a.length + m));
}
catch (ArrayIndexOutOfBoundsException aie) {
@@ -1968,7 +2024,7 @@
try {
Arrays.parallelSort(a, m + 1, m);
- failed("ParallelSort does not throw IllegalArgumentException " +
+ failed("Arrays.parallelSort does not throw IllegalArgumentException " +
" as expected: fromIndex = " + (m + 1) +
" toIndex = " + m);
}
@@ -1976,14 +2032,14 @@
try {
Arrays.parallelSort(a, -m, a.length);
- failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+ failed("Arrays.parallelSort does not throw ArrayIndexOutOfBoundsException " +
" as expected: fromIndex = " + (-m));
}
catch (ArrayIndexOutOfBoundsException aoe) {
try {
Arrays.parallelSort(a, 0, a.length + m);
- failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+ failed("Arrays.parallelSort does not throw ArrayIndexOutOfBoundsException " +
" as expected: toIndex = " + (a.length + m));
}
catch (ArrayIndexOutOfBoundsException aie) {
@@ -1997,7 +2053,7 @@
try {
Arrays.parallelSort(a, m + 1, m);
- failed("ParallelSort does not throw IllegalArgumentException " +
+ failed("Arrays.parallelSort does not throw IllegalArgumentException " +
" as expected: fromIndex = " + (m + 1) +
" toIndex = " + m);
}
@@ -2005,14 +2061,14 @@
try {
Arrays.parallelSort(a, -m, a.length);
- failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+ failed("Arrays.parallelSort does not throw ArrayIndexOutOfBoundsException " +
" as expected: fromIndex = " + (-m));
}
catch (ArrayIndexOutOfBoundsException aoe) {
try {
Arrays.parallelSort(a, 0, a.length + m);
- failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+ failed("Arrays.parallelSort does not throw ArrayIndexOutOfBoundsException " +
" as expected: toIndex = " + (a.length + m));
}
catch (ArrayIndexOutOfBoundsException aie) {
--- old/test/jdk/java/util/Arrays/Sorting.java 2018-01-18 06:09:12.226085321 -0800
+++ new/test/jdk/java/util/Arrays/Sorting.java 2018-01-18 06:09:11.850050426 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -24,20 +24,22 @@
/*
* @test
* @bug 6880672 6896573 6899694 6976036 7013585 7018258
- * @summary Exercise Arrays.sort
* @build Sorting
* @run main Sorting -shortrun
+ * @summary Exercise Arrays.sort
*
* @author Vladimir Yaroslavskiy
* @author Jon Bentley
* @author Josh Bloch
*/
+import java.io.PrintStream;
import java.util.Arrays;
import java.util.Random;
-import java.io.PrintStream;
+import java.util.Comparator;
public class Sorting {
+
private static final PrintStream out = System.out;
private static final PrintStream err = System.err;
@@ -47,7 +49,7 @@
// Array lengths used in a short run
private static final int[] SHORT_RUN_LENGTHS = {
- 1, 2, 3, 21, 55, 1000, 10000 };
+ 1, 2, 3, 21, 55, 1000, 10000, 12000 };
// Random initial values used in a long run (default)
private static final long[] LONG_RUN_RANDOMS = { 666, 0xC0FFEE, 999 };
@@ -55,6 +57,10 @@
// Random initial values used in a short run
private static final long[] SHORT_RUN_RANDOMS = { 666 };
+ // Constant values used in subarray sorting
+ private static final int A380 = 0xA380;
+ private static final int B747 = 0xB747;
+
public static void main(String[] args) {
boolean shortRun = args.length > 0 && args[0].equals("-shortrun");
long start = System.currentTimeMillis();
@@ -79,7 +85,7 @@
testEmptyAndNullDoubleArray();
for (int length : lengths) {
- testMergeSort(length);
+ testMergingSort(length);
testAndCheckRange(length);
testAndCheckSubArray(length);
}
@@ -283,6 +289,15 @@
checkSorted(a);
checkStable(a);
out.println();
+
+ a = build(length, random);
+
+ out.println("Test 'stable' comparator: " + "random = " + random.getSeed() +
+ ", length = " + length);
+ Arrays.sort(a, pairComparator);
+ checkSorted(a);
+ checkStable(a);
+ out.println();
}
private static void checkSorted(Pair[] a) {
@@ -329,6 +344,12 @@
return a;
}
+ private static Comparator pairComparator = new Comparator() {
+ public int compare(Pair p1, Pair p2) {
+ return p1.compareTo(p2);
+ }
+ };
+
private static final class Pair implements Comparable {
Pair(int key, int value) {
myKey = key;
@@ -391,21 +412,21 @@
out.println();
}
- private static void testMergeSort(int length) {
+ private static void testMergingSort(int length) {
if (length < 1000) {
return;
}
- ourDescription = "Check merge sorting";
+ ourDescription = "Check merging sort";
int[] golden = new int[length];
- int period = 67; // java.util.DualPivotQuicksort.MAX_RUN_COUNT
+ final int period = 50;
for (int m = period - 2; m <= period + 2; m++) {
- for (MergeBuilder builder : MergeBuilder.values()) {
+ for (MergingBuilder builder : MergingBuilder.values()) {
builder.build(golden, m);
int[] test = golden.clone();
for (TypeConverter converter : TypeConverter.values()) {
- out.println("Test 'merge sort': " + converter + " " +
+ out.println("Test 'merging sort': " + converter + " " +
builder + "length = " + length + ", m = " + m);
Object convertedGolden = converter.convert(golden);
sort(convertedGolden);
@@ -469,18 +490,15 @@
private static void testAndCheckFloat(int length, MyRandom random) {
ourDescription = "Check float sorting";
float[] golden = new float[length];
- final int MAX = 10;
boolean newLine = false;
+ final int MAX = 12;
for (int a = 0; a <= MAX; a++) {
for (int g = 0; g <= MAX; g++) {
for (int z = 0; z <= MAX; z++) {
for (int n = 0; n <= MAX; n++) {
for (int p = 0; p <= MAX; p++) {
- if (a + g + z + n + p > length) {
- continue;
- }
- if (a + g + z + n + p < length) {
+ if (a + g + z + n + p != length) {
continue;
}
for (FloatBuilder builder : FloatBuilder.values()) {
@@ -544,7 +562,7 @@
private static void prepareSubArray(int[] a, int fromIndex, int toIndex, int m) {
for (int i = 0; i < fromIndex; i++) {
- a[i] = 0xDEDA;
+ a[i] = A380;
}
int middle = (fromIndex + toIndex) >>> 1;
int k = 0;
@@ -556,7 +574,7 @@
a[i] = k--;
}
for (int i = toIndex; i < a.length; i++) {
- a[i] = 0xBABA;
+ a[i] = B747;
}
}
@@ -667,7 +685,7 @@
Integer[] b = new Integer[a.length];
for (int i = 0; i < a.length; i++) {
- b[i] = new Integer(a[i]);
+ b[i] = Integer.valueOf(a[i]);
}
return b;
}
@@ -675,7 +693,8 @@
abstract Object convert(int[] a);
- @Override public String toString() {
+ @Override
+ public String toString() {
String name = name();
for (int i = name.length(); i < 9; i++) {
@@ -828,7 +847,8 @@
abstract void build(int[] a, int m);
- @Override public String toString() {
+ @Override
+ public String toString() {
String name = name();
for (int i = name.length(); i < 12; i++) {
@@ -838,7 +858,7 @@
}
}
- private static enum MergeBuilder {
+ private static enum MergingBuilder {
ASCENDING {
void build(int[] a, int m) {
int period = a.length / m;
@@ -872,11 +892,53 @@
}
a[a.length - 1] = 0;
}
+ },
+ POINT {
+ void build(int[] a, int m) {
+ for (int i = 0; i < a.length; i++) {
+ a[i] = 0;
+ }
+ a[a.length / 2] = m;
+ }
+ },
+ LINE {
+ void build(int[] a, int m) {
+ for (int i = 0; i < a.length; i++) {
+ a[i] = i;
+ }
+ reverse(a, 0, a.length - 1);
+ }
+ },
+ PEARL {
+ void build(int[] a, int m) {
+ for (int i = 0; i < a.length; i++) {
+ a[i] = i;
+ }
+ reverse(a, 0, 2);
+ }
+ },
+ RING {
+ void build(int[] a, int m) {
+ int k1 = a.length / 3;
+ int k2 = a.length / 3 * 2;
+ int level = a.length / 3;
+
+ for (int i = 0, k = level; i < k1; i++) {
+ a[i] = k--;
+ }
+ for (int i = k1; i < k2; i++) {
+ a[i] = 0;
+ }
+ for (int i = k2, k = level; i < a.length; i++) {
+ a[i] = k--;
+ }
+ }
};
abstract void build(int[] a, int m);
- @Override public String toString() {
+ @Override
+ public String toString() {
String name = name();
for (int i = name.length(); i < 12; i++) {
@@ -886,6 +948,14 @@
}
}
+ private static void reverse(int[] a, int lo, int hi) {
+ for (--hi; lo < hi; ) {
+ int tmp = a[lo];
+ a[lo++] = a[hi];
+ a[hi--] = tmp;
+ }
+ }
+
private static enum UnsortedBuilder {
RANDOM {
void build(int[] a, int m, Random random) {
@@ -992,7 +1062,8 @@
abstract void build(int[] a, int m, Random random);
- @Override public String toString() {
+ @Override
+ public String toString() {
String name = name();
for (int i = name.length(); i < 12; i++) {
@@ -1039,7 +1110,7 @@
} else if (test instanceof Integer[]) {
compare((Integer[]) test, (Integer[]) golden);
} else {
- failed("Unknow type of array: " + test + " of class " +
+ failed("Unknown type of array: " + test + " of class " +
test.getClass().getName());
}
}
@@ -1126,7 +1197,7 @@
} else if (object instanceof Integer[]) {
checkSorted((Integer[]) object);
} else {
- failed("Unknow type of array: " + object + " of class " +
+ failed("Unknown type of array: " + object + " of class " +
object.getClass().getName());
}
}
@@ -1222,7 +1293,7 @@
} else if (object instanceof Integer[]) {
return checkSumXor((Integer[]) object);
} else {
- failed("Unknow type of array: " + object + " of class " +
+ failed("Unknown type of array: " + object + " of class " +
object.getClass().getName());
return -1;
}
@@ -1318,7 +1389,7 @@
} else if (object instanceof Integer[]) {
return checkSumPlus((Integer[]) object);
} else {
- failed("Unknow type of array: " + object + " of class " +
+ failed("Unknown type of array: " + object + " of class " +
object.getClass().getName());
return -1;
}
@@ -1414,7 +1485,7 @@
} else if (object instanceof Integer[]) {
sortByInsertionSort((Integer[]) object);
} else {
- failed("Unknow type of array: " + object + " of class " +
+ failed("Unknown type of array: " + object + " of class " +
object.getClass().getName());
}
}
@@ -1517,7 +1588,7 @@
} else if (object instanceof Integer[]) {
Arrays.sort((Integer[]) object);
} else {
- failed("Unknow type of array: " + object + " of class " +
+ failed("Unknown type of array: " + object + " of class " +
object.getClass().getName());
}
}
@@ -1540,7 +1611,7 @@
} else if (object instanceof Integer[]) {
Arrays.sort((Integer[]) object, fromIndex, toIndex);
} else {
- failed("Unknow type of array: " + object + " of class " +
+ failed("Unknown type of array: " + object + " of class " +
object.getClass().getName());
}
}
@@ -1563,16 +1634,16 @@
} else if (object instanceof Integer[]) {
checkSubArray((Integer[]) object, fromIndex, toIndex, m);
} else {
- failed("Unknow type of array: " + object + " of class " +
+ failed("Unknown type of array: " + object + " of class " +
object.getClass().getName());
}
}
private static void checkSubArray(Integer[] a, int fromIndex, int toIndex, int m) {
for (int i = 0; i < fromIndex; i++) {
- if (a[i].intValue() != 0xDEDA) {
+ if (a[i].intValue() != A380) {
failed("Range sort changes left element on position " + i +
- ": " + a[i] + ", must be " + 0xDEDA);
+ ": " + a[i] + ", must be " + A380);
}
}
@@ -1583,18 +1654,18 @@
}
for (int i = toIndex; i < a.length; i++) {
- if (a[i].intValue() != 0xBABA) {
+ if (a[i].intValue() != B747) {
failed("Range sort changes right element on position " + i +
- ": " + a[i] + ", must be " + 0xBABA);
+ ": " + a[i] + ", must be " + B747);
}
}
}
private static void checkSubArray(int[] a, int fromIndex, int toIndex, int m) {
for (int i = 0; i < fromIndex; i++) {
- if (a[i] != 0xDEDA) {
+ if (a[i] != A380) {
failed("Range sort changes left element on position " + i +
- ": " + a[i] + ", must be " + 0xDEDA);
+ ": " + a[i] + ", must be " + A380);
}
}
@@ -1605,18 +1676,18 @@
}
for (int i = toIndex; i < a.length; i++) {
- if (a[i] != 0xBABA) {
+ if (a[i] != B747) {
failed("Range sort changes right element on position " + i +
- ": " + a[i] + ", must be " + 0xBABA);
+ ": " + a[i] + ", must be " + B747);
}
}
}
private static void checkSubArray(byte[] a, int fromIndex, int toIndex, int m) {
for (int i = 0; i < fromIndex; i++) {
- if (a[i] != (byte) 0xDEDA) {
+ if (a[i] != (byte) A380) {
failed("Range sort changes left element on position " + i +
- ": " + a[i] + ", must be " + 0xDEDA);
+ ": " + a[i] + ", must be " + A380);
}
}
@@ -1627,18 +1698,18 @@
}
for (int i = toIndex; i < a.length; i++) {
- if (a[i] != (byte) 0xBABA) {
+ if (a[i] != (byte) B747) {
failed("Range sort changes right element on position " + i +
- ": " + a[i] + ", must be " + 0xBABA);
+ ": " + a[i] + ", must be " + B747);
}
}
}
private static void checkSubArray(long[] a, int fromIndex, int toIndex, int m) {
for (int i = 0; i < fromIndex; i++) {
- if (a[i] != (long) 0xDEDA) {
+ if (a[i] != (long) A380) {
failed("Range sort changes left element on position " + i +
- ": " + a[i] + ", must be " + 0xDEDA);
+ ": " + a[i] + ", must be " + A380);
}
}
@@ -1649,18 +1720,18 @@
}
for (int i = toIndex; i < a.length; i++) {
- if (a[i] != (long) 0xBABA) {
+ if (a[i] != (long) B747) {
failed("Range sort changes right element on position " + i +
- ": " + a[i] + ", must be " + 0xBABA);
+ ": " + a[i] + ", must be " + B747);
}
}
}
private static void checkSubArray(char[] a, int fromIndex, int toIndex, int m) {
for (int i = 0; i < fromIndex; i++) {
- if (a[i] != (char) 0xDEDA) {
+ if (a[i] != (char) A380) {
failed("Range sort changes left element on position " + i +
- ": " + a[i] + ", must be " + 0xDEDA);
+ ": " + a[i] + ", must be " + A380);
}
}
@@ -1671,18 +1742,18 @@
}
for (int i = toIndex; i < a.length; i++) {
- if (a[i] != (char) 0xBABA) {
+ if (a[i] != (char) B747) {
failed("Range sort changes right element on position " + i +
- ": " + a[i] + ", must be " + 0xBABA);
+ ": " + a[i] + ", must be " + B747);
}
}
}
private static void checkSubArray(short[] a, int fromIndex, int toIndex, int m) {
for (int i = 0; i < fromIndex; i++) {
- if (a[i] != (short) 0xDEDA) {
+ if (a[i] != (short) A380) {
failed("Range sort changes left element on position " + i +
- ": " + a[i] + ", must be " + 0xDEDA);
+ ": " + a[i] + ", must be " + A380);
}
}
@@ -1693,18 +1764,18 @@
}
for (int i = toIndex; i < a.length; i++) {
- if (a[i] != (short) 0xBABA) {
+ if (a[i] != (short) B747) {
failed("Range sort changes right element on position " + i +
- ": " + a[i] + ", must be " + 0xBABA);
+ ": " + a[i] + ", must be " + B747);
}
}
}
private static void checkSubArray(float[] a, int fromIndex, int toIndex, int m) {
for (int i = 0; i < fromIndex; i++) {
- if (a[i] != (float) 0xDEDA) {
+ if (a[i] != (float) A380) {
failed("Range sort changes left element on position " + i +
- ": " + a[i] + ", must be " + 0xDEDA);
+ ": " + a[i] + ", must be " + A380);
}
}
@@ -1715,18 +1786,18 @@
}
for (int i = toIndex; i < a.length; i++) {
- if (a[i] != (float) 0xBABA) {
+ if (a[i] != (float) B747) {
failed("Range sort changes right element on position " + i +
- ": " + a[i] + ", must be " + 0xBABA);
+ ": " + a[i] + ", must be " + B747);
}
}
}
private static void checkSubArray(double[] a, int fromIndex, int toIndex, int m) {
for (int i = 0; i < fromIndex; i++) {
- if (a[i] != (double) 0xDEDA) {
+ if (a[i] != (double) A380) {
failed("Range sort changes left element on position " + i +
- ": " + a[i] + ", must be " + 0xDEDA);
+ ": " + a[i] + ", must be " + A380);
}
}
@@ -1737,9 +1808,9 @@
}
for (int i = toIndex; i < a.length; i++) {
- if (a[i] != (double) 0xBABA) {
+ if (a[i] != (double) B747) {
failed("Range sort changes right element on position " + i +
- ": " + a[i] + ", must be " + 0xBABA);
+ ": " + a[i] + ", must be " + B747);
}
}
}
@@ -1762,7 +1833,7 @@
} else if (object instanceof Integer[]) {
checkRange((Integer[]) object, m);
} else {
- failed("Unknow type of array: " + object + " of class " +
+ failed("Unknown type of array: " + object + " of class " +
object.getClass().getName());
}
}
@@ -1771,7 +1842,7 @@
try {
Arrays.sort(a, m + 1, m);
- failed("Sort does not throw IllegalArgumentException " +
+ failed("Arrays.sort does not throw IllegalArgumentException " +
" as expected: fromIndex = " + (m + 1) +
" toIndex = " + m);
}
@@ -1779,14 +1850,14 @@
try {
Arrays.sort(a, -m, a.length);
- failed("Sort does not throw ArrayIndexOutOfBoundsException " +
+ failed("Arrays.sort does not throw ArrayIndexOutOfBoundsException " +
" as expected: fromIndex = " + (-m));
}
catch (ArrayIndexOutOfBoundsException aoe) {
try {
Arrays.sort(a, 0, a.length + m);
- failed("Sort does not throw ArrayIndexOutOfBoundsException " +
+ failed("Arrays.sort does not throw ArrayIndexOutOfBoundsException " +
" as expected: toIndex = " + (a.length + m));
}
catch (ArrayIndexOutOfBoundsException aie) {
@@ -1800,7 +1871,7 @@
try {
Arrays.sort(a, m + 1, m);
- failed("Sort does not throw IllegalArgumentException " +
+ failed("Arrays.sort does not throw IllegalArgumentException " +
" as expected: fromIndex = " + (m + 1) +
" toIndex = " + m);
}
@@ -1808,14 +1879,14 @@
try {
Arrays.sort(a, -m, a.length);
- failed("Sort does not throw ArrayIndexOutOfBoundsException " +
+ failed("Arrays.sort does not throw ArrayIndexOutOfBoundsException " +
" as expected: fromIndex = " + (-m));
}
catch (ArrayIndexOutOfBoundsException aoe) {
try {
Arrays.sort(a, 0, a.length + m);
- failed("Sort does not throw ArrayIndexOutOfBoundsException " +
+ failed("Arrays.sort does not throw ArrayIndexOutOfBoundsException " +
" as expected: toIndex = " + (a.length + m));
}
catch (ArrayIndexOutOfBoundsException aie) {
@@ -1829,7 +1900,7 @@
try {
Arrays.sort(a, m + 1, m);
- failed("Sort does not throw IllegalArgumentException " +
+ failed("Arrays.sort does not throw IllegalArgumentException " +
" as expected: fromIndex = " + (m + 1) +
" toIndex = " + m);
}
@@ -1837,14 +1908,14 @@
try {
Arrays.sort(a, -m, a.length);
- failed("Sort does not throw ArrayIndexOutOfBoundsException " +
+ failed("Arrays.sort does not throw ArrayIndexOutOfBoundsException " +
" as expected: fromIndex = " + (-m));
}
catch (ArrayIndexOutOfBoundsException aoe) {
try {
Arrays.sort(a, 0, a.length + m);
- failed("Sort does not throw ArrayIndexOutOfBoundsException " +
+ failed("Arrays.sort does not throw ArrayIndexOutOfBoundsException " +
" as expected: toIndex = " + (a.length + m));
}
catch (ArrayIndexOutOfBoundsException aie) {
@@ -1858,7 +1929,7 @@
try {
Arrays.sort(a, m + 1, m);
- failed("Sort does not throw IllegalArgumentException " +
+ failed("Arrays.sort does not throw IllegalArgumentException " +
" as expected: fromIndex = " + (m + 1) +
" toIndex = " + m);
}
@@ -1866,14 +1937,14 @@
try {
Arrays.sort(a, -m, a.length);
- failed("Sort does not throw ArrayIndexOutOfBoundsException " +
+ failed("Arrays.sort does not throw ArrayIndexOutOfBoundsException " +
" as expected: fromIndex = " + (-m));
}
catch (ArrayIndexOutOfBoundsException aoe) {
try {
Arrays.sort(a, 0, a.length + m);
- failed("Sort does not throw ArrayIndexOutOfBoundsException " +
+ failed("Arrays.sort does not throw ArrayIndexOutOfBoundsException " +
" as expected: toIndex = " + (a.length + m));
}
catch (ArrayIndexOutOfBoundsException aie) {
@@ -1887,7 +1958,7 @@
try {
Arrays.sort(a, m + 1, m);
- failed("Sort does not throw IllegalArgumentException " +
+ failed("Arrays.sort does not throw IllegalArgumentException " +
" as expected: fromIndex = " + (m + 1) +
" toIndex = " + m);
}
@@ -1895,14 +1966,14 @@
try {
Arrays.sort(a, -m, a.length);
- failed("Sort does not throw ArrayIndexOutOfBoundsException " +
+ failed("Arrays.sort does not throw ArrayIndexOutOfBoundsException " +
" as expected: fromIndex = " + (-m));
}
catch (ArrayIndexOutOfBoundsException aoe) {
try {
Arrays.sort(a, 0, a.length + m);
- failed("Sort does not throw ArrayIndexOutOfBoundsException " +
+ failed("Arrays.sort does not throw ArrayIndexOutOfBoundsException " +
" as expected: toIndex = " + (a.length + m));
}
catch (ArrayIndexOutOfBoundsException aie) {
@@ -1916,7 +1987,7 @@
try {
Arrays.sort(a, m + 1, m);
- failed("Sort does not throw IllegalArgumentException " +
+ failed("Arrays.sort does not throw IllegalArgumentException " +
" as expected: fromIndex = " + (m + 1) +
" toIndex = " + m);
}
@@ -1924,14 +1995,14 @@
try {
Arrays.sort(a, -m, a.length);
- failed("Sort does not throw ArrayIndexOutOfBoundsException " +
+ failed("Arrays.sort does not throw ArrayIndexOutOfBoundsException " +
" as expected: fromIndex = " + (-m));
}
catch (ArrayIndexOutOfBoundsException aoe) {
try {
Arrays.sort(a, 0, a.length + m);
- failed("Sort does not throw ArrayIndexOutOfBoundsException " +
+ failed("Arrays.sort does not throw ArrayIndexOutOfBoundsException " +
" as expected: toIndex = " + (a.length + m));
}
catch (ArrayIndexOutOfBoundsException aie) {
@@ -1945,7 +2016,7 @@
try {
Arrays.sort(a, m + 1, m);
- failed("Sort does not throw IllegalArgumentException " +
+ failed("Arrays.sort does not throw IllegalArgumentException " +
" as expected: fromIndex = " + (m + 1) +
" toIndex = " + m);
}
@@ -1953,14 +2024,14 @@
try {
Arrays.sort(a, -m, a.length);
- failed("Sort does not throw ArrayIndexOutOfBoundsException " +
+ failed("Arrays.sort does not throw ArrayIndexOutOfBoundsException " +
" as expected: fromIndex = " + (-m));
}
catch (ArrayIndexOutOfBoundsException aoe) {
try {
Arrays.sort(a, 0, a.length + m);
- failed("Sort does not throw ArrayIndexOutOfBoundsException " +
+ failed("Arrays.sort does not throw ArrayIndexOutOfBoundsException " +
" as expected: toIndex = " + (a.length + m));
}
catch (ArrayIndexOutOfBoundsException aie) {
@@ -1974,7 +2045,7 @@
try {
Arrays.sort(a, m + 1, m);
- failed("Sort does not throw IllegalArgumentException " +
+ failed("Arrays.sort does not throw IllegalArgumentException " +
" as expected: fromIndex = " + (m + 1) +
" toIndex = " + m);
}
@@ -1982,14 +2053,14 @@
try {
Arrays.sort(a, -m, a.length);
- failed("Sort does not throw ArrayIndexOutOfBoundsException " +
+ failed("Arrays.sort does not throw ArrayIndexOutOfBoundsException " +
" as expected: fromIndex = " + (-m));
}
catch (ArrayIndexOutOfBoundsException aoe) {
try {
Arrays.sort(a, 0, a.length + m);
- failed("Sort does not throw ArrayIndexOutOfBoundsException " +
+ failed("Arrays.sort does not throw ArrayIndexOutOfBoundsException " +
" as expected: toIndex = " + (a.length + m));
}
catch (ArrayIndexOutOfBoundsException aie) {
--- /dev/null 2017-10-28 23:52:53.434169431 -0700
+++ new/src/java.base/share/classes/java/util/SortingAlgorithms.java 2018-01-18 06:09:12.560116317 -0800
@@ -0,0 +1,1791 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.util.concurrent.ForkJoinTask;
+import java.util.concurrent.RecursiveTask;
+
+/**
+ * This class implements sorting algorithms by Vladimir Yaroslavskiy,
+ such as Merging sort, the pair, nano and optimized insertion sorts,
+ * counting sort and heap sort, invoked from the Dual-Pivot Quicksort.
+ *
+ * @author Vladimir Yaroslavskiy
+ *
+ * @version 2018.02.18
+ * @since 10
+ */
+final class SortingAlgorithms {
+
+ /**
+ * Prevents instantiation.
+ */
+ private SortingAlgorithms() {}
+
+ /**
+ * The minimal number of runs, required by parallel Merging sort.
+ */
+ private static final int MIN_PARALLEL_RUNS_COUNT = 4;
+
+ /**
+ * If the length of an array to be sorted is greater than this
+ * constant, Merging sort is used in preference to Quicksort.
+ */
+ private static final int MERGING_SORT_THRESHOLD = 2048;
+
+ /**
+ * Calculates the maximum number of runs.
+ *
+ * @param length the array length
+ * @return the maximum number of runs
+ */
+ private static int getMaxRunCount(int length) {
+ return length > 2048000 ? 2000 : length >> 10 | 5;
+ }
+
+ /**
+ * This class implements the parallel Merging sort.
+ */
+ @SuppressWarnings("serial")
+ private static class Merger extends RecursiveTask {
+
+ Merger(T a, T b, boolean src, int offset, int[] run, int lo, int hi) {
+ this.a = a;
+ this.b = b;
+ this.src = src;
+ this.offset = offset;
+ this.run = run;
+ this.lo = lo;
+ this.hi = hi;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ protected T compute() {
+ Class> clazz = a.getClass();
+
+ if (clazz == int[].class) {
+ return (T) merge((int[]) a, (int[]) b, src, true, offset, run, lo, hi);
+ }
+ if (clazz == long[].class) {
+ return (T) merge((long[]) a, (long[]) b, src, true, offset, run, lo, hi);
+ }
+ if (clazz == char[].class) {
+ return (T) merge((char[]) a, (char[]) b, src, true, offset, run, lo, hi);
+ }
+ if (clazz == short[].class) {
+ return (T) merge((short[]) a, (short[]) b, src, true, offset, run, lo, hi);
+ }
+ if (clazz == float[].class) {
+ return (T) merge((float[]) a, (float[]) b, src, true, offset, run, lo, hi);
+ }
+ if (clazz == double[].class) {
+ return (T) merge((double[]) a, (double[]) b, src, true, offset, run, lo, hi);
+ }
+ throw new IllegalArgumentException(
+ "Unknown type of array: " + clazz.getName());
+ }
+
+ private T a;
+ private T b;
+ private boolean src;
+ private int offset;
+ private int[] run;
+ private int lo;
+ private int hi;
+ }
+
+ /**
+ * Tries to sort the specified range of the array by the Merging sort.
+ *
+ * @param a the array to be sorted
+ * @param parallel indicates whether merging is performed in parallel
+ * @param low the index of the first element, inclusive, to be sorted
+ * @param high the index of the last element, exclusive, to be sorted
+ * @return true if the given array is finally sorted, false otherwise
+ */
+ static boolean mergingSort(int[] a, boolean parallel, int low, int high) {
+ int length = high - low;
+
+ if (length < MERGING_SORT_THRESHOLD) {
+ return false;
+ }
+
+ /*
+ * Index run[i] is the start of i-th run.
+ * A run is a subsequence of elements
+ * in ascending or descending order.
+ */
+ int max = getMaxRunCount(length);
+ int[] run = new int[max + 1];
+ int count = 0, last = low; run[0] = low;
+
+ /*
+ * Check if the array is highly structured.
+ */
+ for (int k = low + 1; k < high && count < max; ) {
+ if (a[k - 1] < a[k]) {
+
+ // Identify ascending sequence
+ while (++k < high && a[k - 1] <= a[k]);
+
+ } else if (a[k - 1] > a[k]) {
+
+ // Identify descending sequence
+ while (++k < high && a[k - 1] >= a[k]);
+
+ // Reverse the run into ascending order
+ for (int i = last - 1, j = k; ++i < --j && a[i] > a[j]; ) {
+ int ai = a[i]; a[i] = a[j]; a[j] = ai;
+ }
+ } else { // Sequence with equal elements
+ for (int ak = a[k]; ++k < high && ak == a[k]; );
+
+ if (k < high) {
+ continue;
+ }
+ }
+
+ if (count == 0 || a[last - 1] > a[last]) {
+ ++count;
+ }
+ run[count] = (last = k);
+ }
+
+ if (count < max && count > 1) {
+ /*
+ * The array is highly structured, therefore merge all runs.
+ */
+ merge(a, new int[length], true, parallel, low, run, 0, count);
+ }
+ return count < max;
+ }
+
+ /**
+ * Merges the specified runs.
+ *
+ * @param a the source array
+ * @param b the temporary buffer
+ * @param src specifies the type of the target: source or buffer
+ * @param parallel indicates whether merging is performed in parallel
+ * @param offset the start index of the source, inclusive
+ * @param run the start indexes of the runs, inclusive
+ * @param lo the start index of the first run, inclusive
+ * @param hi the start index of the last run, inclusive
+ * @return the target where runs are merged
+ */
+ private static int[] merge(int[] a, int[] b, boolean src,
+ boolean parallel, int offset, int[] run, int lo, int hi) {
+
+ if (hi - lo == 1) {
+ if (src) {
+ return a;
+ }
+ for (int i = run[hi], j = i - offset, low = run[lo]; i > low;
+ b[--j] = a[--i]
+ );
+ return b;
+ }
+ int mi = (lo + hi) >>> 1;
+
+ int[] a1, a2; // the left and the right halves to be merged
+
+ if (parallel && hi - lo > MIN_PARALLEL_RUNS_COUNT) {
+ Merger merger1 = new Merger(a, b, !src, offset, run, lo, mi);
+ Merger merger2 = new Merger(a, b, true, offset, run, mi, hi);
+
+ ForkJoinTask.invokeAll(merger1, merger2);
+
+ a1 = merger1.getRawResult();
+ a2 = merger2.getRawResult();
+ } else {
+ a1 = merge(a, b, !src, false, offset, run, lo, mi);
+ a2 = merge(a, b, true, false, offset, run, mi, hi);
+ }
+ return merge(
+ a1 == a ? b : a,
+ a1 == a ? run[lo] - offset : run[lo],
+ a1,
+ a1 == b ? run[lo] - offset : run[lo],
+ a1 == b ? run[mi] - offset : run[mi],
+ a2,
+ a2 == b ? run[mi] - offset : run[mi],
+ a2 == b ? run[hi] - offset : run[hi]);
+ }
+
+ /**
+ * Merges the sorted halves.
+ *
+ * @param dst the destination where halves are merged
+ * @param k the start index of the destination, inclusive
+ * @param a1 the first half
+ * @param i the start index of the first half, inclusive
+ * @param hi the end index of the first half, exclusive
+ * @param a2 the second half
+ * @param j the start index of the second half, inclusive
+ * @param hj the end index of the second half, exclusive
+ * @return the merged halves
+ */
+ private static int[] merge(int[] dst, int k,
+ int[] a1, int i, int hi, int[] a2, int j, int hj) {
+
+ while (true) {
+ dst[k++] = a1[i] < a2[j] ? a1[i++] : a2[j++];
+
+ if (i == hi) {
+ while (j < hj) {
+ dst[k++] = a2[j++];
+ }
+ return dst;
+ }
+ if (j == hj) {
+ while (i < hi) {
+ dst[k++] = a1[i++];
+ }
+ return dst;
+ }
+ }
+ }
+
+ /**
+ * Tries to sort the specified range of the array by the Merging sort.
+ *
+ * @param a the array to be sorted
+ * @param parallel indicates whether merging is performed in parallel
+ * @param low the index of the first element, inclusive, to be sorted
+ * @param high the index of the last element, exclusive, to be sorted
+ * @return true if the given array is finally sorted, false otherwise
+ */
+ static boolean mergingSort(long[] a, boolean parallel, int low, int high) {
+ int length = high - low;
+
+ if (length < MERGING_SORT_THRESHOLD) {
+ return false;
+ }
+
+ /*
+ * Index run[i] is the start of i-th run.
+ * A run is a subsequence of elements
+ * in ascending or descending order.
+ */
+ int max = getMaxRunCount(length);
+ int[] run = new int[max + 1];
+ int count = 0, last = low; run[0] = low;
+
+ /*
+ * Check if the array is highly structured.
+ */
+ for (int k = low + 1; k < high && count < max; ) {
+ if (a[k - 1] < a[k]) {
+
+ // Identify ascending sequence
+ while (++k < high && a[k - 1] <= a[k]);
+
+ } else if (a[k - 1] > a[k]) {
+
+ // Identify descending sequence
+ while (++k < high && a[k - 1] >= a[k]);
+
+ // Reverse the run into ascending order
+ for (int i = last - 1, j = k; ++i < --j && a[i] > a[j]; ) {
+ long ai = a[i]; a[i] = a[j]; a[j] = ai;
+ }
+ } else { // Sequence with equal elements
+ for (long ak = a[k]; ++k < high && ak == a[k]; );
+
+ if (k < high) {
+ continue;
+ }
+ }
+
+ if (count == 0 || a[last - 1] > a[last]) {
+ ++count;
+ }
+ run[count] = (last = k);
+ }
+
+ if (count < max && count > 1) {
+ /*
+ * The array is highly structured, therefore merge all runs.
+ */
+ merge(a, new long[length], true, parallel, low, run, 0, count);
+ }
+ return count < max;
+ }
+
+ /**
+ * Merges the specified runs.
+ *
+ * @param a the source array
+ * @param b the temporary buffer
+ * @param src specifies the type of the target: source or buffer
+ * @param parallel indicates whether merging is performed in parallel
+ * @param offset the start index of the source, inclusive
+ * @param run the start indexes of the runs, inclusive
+ * @param lo the start index of the first run, inclusive
+ * @param hi the start index of the last run, inclusive
+ * @return the target where runs are merged
+ */
+ private static long[] merge(long[] a, long[] b, boolean src,
+ boolean parallel, int offset, int[] run, int lo, int hi) {
+
+ if (hi - lo == 1) {
+ if (src) {
+ return a;
+ }
+ for (int i = run[hi], j = i - offset, low = run[lo]; i > low;
+ b[--j] = a[--i]
+ );
+ return b;
+ }
+ int mi = (lo + hi) >>> 1;
+
+ long[] a1, a2; // the left and the right halves to be merged
+
+ if (parallel && hi - lo > MIN_PARALLEL_RUNS_COUNT) {
+ Merger merger1 = new Merger(a, b, !src, offset, run, lo, mi);
+ Merger merger2 = new Merger(a, b, true, offset, run, mi, hi);
+
+ ForkJoinTask.invokeAll(merger1, merger2);
+
+ a1 = merger1.getRawResult();
+ a2 = merger2.getRawResult();
+ } else {
+ a1 = merge(a, b, !src, false, offset, run, lo, mi);
+ a2 = merge(a, b, true, false, offset, run, mi, hi);
+ }
+ return merge(
+ a1 == a ? b : a,
+ a1 == a ? run[lo] - offset : run[lo],
+ a1,
+ a1 == b ? run[lo] - offset : run[lo],
+ a1 == b ? run[mi] - offset : run[mi],
+ a2,
+ a2 == b ? run[mi] - offset : run[mi],
+ a2 == b ? run[hi] - offset : run[hi]);
+ }
+
+ /**
+ * Merges the sorted halves.
+ *
+ * @param dst the destination where halves are merged
+ * @param k the start index of the destination, inclusive
+ * @param a1 the first half
+ * @param i the start index of the first half, inclusive
+ * @param hi the end index of the first half, exclusive
+ * @param a2 the second half
+ * @param j the start index of the second half, inclusive
+ * @param hj the end index of the second half, exclusive
+ * @return the merged halves
+ */
+ private static long[] merge(long[] dst, int k,
+ long[] a1, int i, int hi, long[] a2, int j, int hj) {
+
+ while (true) {
+ dst[k++] = a1[i] < a2[j] ? a1[i++] : a2[j++];
+
+ if (i == hi) {
+ while (j < hj) {
+ dst[k++] = a2[j++];
+ }
+ return dst;
+ }
+ if (j == hj) {
+ while (i < hi) {
+ dst[k++] = a1[i++];
+ }
+ return dst;
+ }
+ }
+ }
+
+ /**
+ * Tries to sort the specified range of the array by the Merging sort.
+ *
+ * @param a the array to be sorted
+ * @param parallel indicates whether merging is performed in parallel
+ * @param low the index of the first element, inclusive, to be sorted
+ * @param high the index of the last element, exclusive, to be sorted
+ * @return true if the given array is finally sorted, false otherwise
+ */
+ static boolean mergingSort(char[] a, boolean parallel, int low, int high) {
+ int length = high - low;
+
+ if (length < MERGING_SORT_THRESHOLD) {
+ return false;
+ }
+
+ /*
+ * Index run[i] is the start of i-th run.
+ * A run is a subsequence of elements
+ * in ascending or descending order.
+ */
+ int max = getMaxRunCount(length);
+ int[] run = new int[max + 1];
+ int count = 0, last = low; run[0] = low;
+
+ /*
+ * Check if the array is highly structured.
+ */
+ for (int k = low + 1; k < high && count < max; ) {
+ if (a[k - 1] < a[k]) {
+
+ // Identify ascending sequence
+ while (++k < high && a[k - 1] <= a[k]);
+
+ } else if (a[k - 1] > a[k]) {
+
+ // Identify descending sequence
+ while (++k < high && a[k - 1] >= a[k]);
+
+ // Reverse the run into ascending order
+ for (int i = last - 1, j = k; ++i < --j && a[i] > a[j]; ) {
+ char ai = a[i]; a[i] = a[j]; a[j] = ai;
+ }
+ } else { // Sequence with equal elements
+ for (char ak = a[k]; ++k < high && ak == a[k]; );
+
+ if (k < high) {
+ continue;
+ }
+ }
+
+ if (count == 0 || a[last - 1] > a[last]) {
+ ++count;
+ }
+ run[count] = (last = k);
+ }
+
+ if (count < max && count > 1) {
+ /*
+ * The array is highly structured, therefore merge all runs.
+ */
+ merge(a, new char[length], true, parallel, low, run, 0, count);
+ }
+ return count < max;
+ }
+
+ /**
+ * Merges the specified runs.
+ *
+ * @param a the source array
+ * @param b the temporary buffer
+ * @param src specifies the type of the target: source or buffer
+ * @param parallel indicates whether merging is performed in parallel
+ * @param offset the start index of the source, inclusive
+ * @param run the start indexes of the runs, inclusive
+ * @param lo the start index of the first run, inclusive
+ * @param hi the start index of the last run, inclusive
+ * @return the target where runs are merged
+ */
+ private static char[] merge(char[] a, char[] b, boolean src,
+ boolean parallel, int offset, int[] run, int lo, int hi) {
+
+ if (hi - lo == 1) {
+ if (src) {
+ return a;
+ }
+ for (int i = run[hi], j = i - offset, low = run[lo]; i > low;
+ b[--j] = a[--i]
+ );
+ return b;
+ }
+ int mi = (lo + hi) >>> 1;
+
+ char[] a1, a2; // the left and the right halves to be merged
+
+ if (parallel && hi - lo > MIN_PARALLEL_RUNS_COUNT) {
+ Merger merger1 = new Merger(a, b, !src, offset, run, lo, mi);
+ Merger merger2 = new Merger(a, b, true, offset, run, mi, hi);
+
+ ForkJoinTask.invokeAll(merger1, merger2);
+
+ a1 = merger1.getRawResult();
+ a2 = merger2.getRawResult();
+ } else {
+ a1 = merge(a, b, !src, false, offset, run, lo, mi);
+ a2 = merge(a, b, true, false, offset, run, mi, hi);
+ }
+ return merge(
+ a1 == a ? b : a,
+ a1 == a ? run[lo] - offset : run[lo],
+ a1,
+ a1 == b ? run[lo] - offset : run[lo],
+ a1 == b ? run[mi] - offset : run[mi],
+ a2,
+ a2 == b ? run[mi] - offset : run[mi],
+ a2 == b ? run[hi] - offset : run[hi]);
+ }
+
+ /**
+ * Merges the sorted halves.
+ *
+ * @param dst the destination where halves are merged
+ * @param k the start index of the destination, inclusive
+ * @param a1 the first half
+ * @param i the start index of the first half, inclusive
+ * @param hi the end index of the first half, exclusive
+ * @param a2 the second half
+ * @param j the start index of the second half, inclusive
+ * @param hj the end index of the second half, exclusive
+ * @return the merged halves
+ */
+ private static char[] merge(char[] dst, int k,
+ char[] a1, int i, int hi, char[] a2, int j, int hj) {
+
+ while (true) {
+ dst[k++] = a1[i] < a2[j] ? a1[i++] : a2[j++];
+
+ if (i == hi) {
+ while (j < hj) {
+ dst[k++] = a2[j++];
+ }
+ return dst;
+ }
+ if (j == hj) {
+ while (i < hi) {
+ dst[k++] = a1[i++];
+ }
+ return dst;
+ }
+ }
+ }
+
+ /**
+ * Tries to sort the specified range of the array by the Merging sort.
+ *
+ * @param a the array to be sorted
+ * @param parallel indicates whether merging is performed in parallel
+ * @param low the index of the first element, inclusive, to be sorted
+ * @param high the index of the last element, exclusive, to be sorted
+ * @return true if the given array is finally sorted, false otherwise
+ */
+ static boolean mergingSort(short[] a, boolean parallel, int low, int high) {
+ int length = high - low;
+
+ if (length < MERGING_SORT_THRESHOLD) {
+ return false;
+ }
+
+ /*
+ * Index run[i] is the start of i-th run.
+ * A run is a subsequence of elements
+ * in ascending or descending order.
+ */
+ int max = getMaxRunCount(length);
+ int[] run = new int[max + 1];
+ int count = 0, last = low; run[0] = low;
+
+ /*
+ * Check if the array is highly structured.
+ */
+ for (int k = low + 1; k < high && count < max; ) {
+ if (a[k - 1] < a[k]) {
+
+ // Identify ascending sequence
+ while (++k < high && a[k - 1] <= a[k]);
+
+ } else if (a[k - 1] > a[k]) {
+
+ // Identify descending sequence
+ while (++k < high && a[k - 1] >= a[k]);
+
+ // Reverse the run into ascending order
+ for (int i = last - 1, j = k; ++i < --j && a[i] > a[j]; ) {
+ short ai = a[i]; a[i] = a[j]; a[j] = ai;
+ }
+ } else { // Sequence with equal elements
+ for (short ak = a[k]; ++k < high && ak == a[k]; );
+
+ if (k < high) {
+ continue;
+ }
+ }
+
+ if (count == 0 || a[last - 1] > a[last]) {
+ ++count;
+ }
+ run[count] = (last = k);
+ }
+
+ if (count < max && count > 1) {
+ /*
+ * The array is highly structured, therefore merge all runs.
+ */
+ merge(a, new short[length], true, parallel, low, run, 0, count);
+ }
+ return count < max;
+ }
+
+ /**
+ * Merges the specified runs.
+ *
+ * @param a the source array
+ * @param b the temporary buffer
+ * @param src specifies the type of the target: source or buffer
+ * @param parallel indicates whether merging is performed in parallel
+ * @param offset the start index of the source, inclusive
+ * @param run the start indexes of the runs, inclusive
+ * @param lo the start index of the first run, inclusive
+ * @param hi the start index of the last run, inclusive
+ * @return the target where runs are merged
+ */
+ private static short[] merge(short[] a, short[] b, boolean src,
+ boolean parallel, int offset, int[] run, int lo, int hi) {
+
+ if (hi - lo == 1) {
+ if (src) {
+ return a;
+ }
+ for (int i = run[hi], j = i - offset, low = run[lo]; i > low;
+ b[--j] = a[--i]
+ );
+ return b;
+ }
+ int mi = (lo + hi) >>> 1;
+
+ short[] a1, a2; // the left and the right halves to be merged
+
+ if (parallel && hi - lo > MIN_PARALLEL_RUNS_COUNT) {
+ Merger merger1 = new Merger(a, b, !src, offset, run, lo, mi);
+ Merger merger2 = new Merger(a, b, true, offset, run, mi, hi);
+
+ ForkJoinTask.invokeAll(merger1, merger2);
+
+ a1 = merger1.getRawResult();
+ a2 = merger2.getRawResult();
+ } else {
+ a1 = merge(a, b, !src, false, offset, run, lo, mi);
+ a2 = merge(a, b, true, false, offset, run, mi, hi);
+ }
+ return merge(
+ a1 == a ? b : a,
+ a1 == a ? run[lo] - offset : run[lo],
+ a1,
+ a1 == b ? run[lo] - offset : run[lo],
+ a1 == b ? run[mi] - offset : run[mi],
+ a2,
+ a2 == b ? run[mi] - offset : run[mi],
+ a2 == b ? run[hi] - offset : run[hi]);
+ }
+
+ /**
+ * Merges the sorted halves.
+ *
+ * @param dst the destination where halves are merged
+ * @param k the start index of the destination, inclusive
+ * @param a1 the first half
+ * @param i the start index of the first half, inclusive
+ * @param hi the end index of the first half, exclusive
+ * @param a2 the second half
+ * @param j the start index of the second half, inclusive
+ * @param hj the end index of the second half, exclusive
+ * @return the merged halves
+ */
+ private static short[] merge(short[] dst, int k,
+ short[] a1, int i, int hi, short[] a2, int j, int hj) {
+
+ while (true) {
+ dst[k++] = a1[i] < a2[j] ? a1[i++] : a2[j++];
+
+ if (i == hi) {
+ while (j < hj) {
+ dst[k++] = a2[j++];
+ }
+ return dst;
+ }
+ if (j == hj) {
+ while (i < hi) {
+ dst[k++] = a1[i++];
+ }
+ return dst;
+ }
+ }
+ }
+
+ /**
+ * Tries to sort the specified range of the array by the Merging sort.
+ *
+ * @param a the array to be sorted
+ * @param parallel indicates whether merging is performed in parallel
+ * @param low the index of the first element, inclusive, to be sorted
+ * @param high the index of the last element, exclusive, to be sorted
+ * @return true if the given array is finally sorted, false otherwise
+ */
+ static boolean mergingSort(float[] a, boolean parallel, int low, int high) {
+ int length = high - low;
+
+ if (length < MERGING_SORT_THRESHOLD) {
+ return false;
+ }
+
+ /*
+ * Index run[i] is the start of i-th run.
+ * A run is a subsequence of elements
+ * in ascending or descending order.
+ */
+ int max = getMaxRunCount(length);
+ int[] run = new int[max + 1];
+ int count = 0, last = low; run[0] = low;
+
+ /*
+ * Check if the array is highly structured.
+ */
+ for (int k = low + 1; k < high && count < max; ) {
+ if (a[k - 1] < a[k]) {
+
+ // Identify ascending sequence
+ while (++k < high && a[k - 1] <= a[k]);
+
+ } else if (a[k - 1] > a[k]) {
+
+ // Identify descending sequence
+ while (++k < high && a[k - 1] >= a[k]);
+
+ // Reverse the run into ascending order
+ for (int i = last - 1, j = k; ++i < --j && a[i] > a[j]; ) {
+ float ai = a[i]; a[i] = a[j]; a[j] = ai;
+ }
+ } else { // Sequence with equal elements
+ for (float ak = a[k]; ++k < high && ak == a[k]; );
+
+ if (k < high) {
+ continue;
+ }
+ }
+
+ if (count == 0 || a[last - 1] > a[last]) {
+ ++count;
+ }
+ run[count] = (last = k);
+ }
+
+ if (count < max && count > 1) {
+ /*
+ * The array is highly structured, therefore merge all runs.
+ */
+ merge(a, new float[length], true, parallel, low, run, 0, count);
+ }
+ return count < max;
+ }
+
+ /**
+ * Merges the specified runs.
+ *
+ * @param a the source array
+ * @param b the temporary buffer
+ * @param src specifies the type of the target: source or buffer
+ * @param parallel indicates whether merging is performed in parallel
+ * @param offset the start index of the source, inclusive
+ * @param run the start indexes of the runs, inclusive
+ * @param lo the start index of the first run, inclusive
+ * @param hi the start index of the last run, inclusive
+ * @return the target where runs are merged
+ */
+ private static float[] merge(float[] a, float[] b, boolean src,
+ boolean parallel, int offset, int[] run, int lo, int hi) {
+
+ if (hi - lo == 1) {
+ if (src) {
+ return a;
+ }
+ for (int i = run[hi], j = i - offset, low = run[lo]; i > low;
+ b[--j] = a[--i]
+ );
+ return b;
+ }
+ int mi = (lo + hi) >>> 1;
+
+ float[] a1, a2; // the left and the right halves to be merged
+
+ if (parallel && hi - lo > MIN_PARALLEL_RUNS_COUNT) {
+ Merger merger1 = new Merger(a, b, !src, offset, run, lo, mi);
+ Merger merger2 = new Merger(a, b, true, offset, run, mi, hi);
+
+ ForkJoinTask.invokeAll(merger1, merger2);
+
+ a1 = merger1.getRawResult();
+ a2 = merger2.getRawResult();
+ } else {
+ a1 = merge(a, b, !src, false, offset, run, lo, mi);
+ a2 = merge(a, b, true, false, offset, run, mi, hi);
+ }
+ return merge(
+ a1 == a ? b : a,
+ a1 == a ? run[lo] - offset : run[lo],
+ a1,
+ a1 == b ? run[lo] - offset : run[lo],
+ a1 == b ? run[mi] - offset : run[mi],
+ a2,
+ a2 == b ? run[mi] - offset : run[mi],
+ a2 == b ? run[hi] - offset : run[hi]);
+ }
+
+ /**
+ * Merges the sorted halves.
+ *
+ * @param dst the destination where halves are merged
+ * @param k the start index of the destination, inclusive
+ * @param a1 the first half
+ * @param i the start index of the first half, inclusive
+ * @param hi the end index of the first half, exclusive
+ * @param a2 the second half
+ * @param j the start index of the second half, inclusive
+ * @param hj the end index of the second half, exclusive
+ * @return the merged halves
+ */
+ private static float[] merge(float[] dst, int k,
+ float[] a1, int i, int hi, float[] a2, int j, int hj) {
+
+ while (true) {
+ dst[k++] = a1[i] < a2[j] ? a1[i++] : a2[j++];
+
+ if (i == hi) {
+ while (j < hj) {
+ dst[k++] = a2[j++];
+ }
+ return dst;
+ }
+ if (j == hj) {
+ while (i < hi) {
+ dst[k++] = a1[i++];
+ }
+ return dst;
+ }
+ }
+ }
+
+ /**
+ * Tries to sort the specified range of the array by the Merging sort.
+ *
+ * @param a the array to be sorted
+ * @param parallel indicates whether merging is performed in parallel
+ * @param low the index of the first element, inclusive, to be sorted
+ * @param high the index of the last element, exclusive, to be sorted
+ * @return true if the given array is finally sorted, false otherwise
+ */
+ static boolean mergingSort(double[] a, boolean parallel, int low, int high) {
+ int length = high - low;
+
+ if (length < MERGING_SORT_THRESHOLD) {
+ return false;
+ }
+
+ /*
+ * Index run[i] is the start of i-th run.
+ * A run is a subsequence of elements
+ * in ascending or descending order.
+ */
+ int max = getMaxRunCount(length);
+ int[] run = new int[max + 1];
+ int count = 0, last = low; run[0] = low;
+
+ /*
+ * Check if the array is highly structured.
+ */
+ for (int k = low + 1; k < high && count < max; ) {
+ if (a[k - 1] < a[k]) {
+
+ // Identify ascending sequence
+ while (++k < high && a[k - 1] <= a[k]);
+
+ } else if (a[k - 1] > a[k]) {
+
+ // Identify descending sequence
+ while (++k < high && a[k - 1] >= a[k]);
+
+ // Reverse the run into ascending order
+ for (int i = last - 1, j = k; ++i < --j && a[i] > a[j]; ) {
+ double ai = a[i]; a[i] = a[j]; a[j] = ai;
+ }
+ } else { // Sequence with equal elements
+ for (double ak = a[k]; ++k < high && ak == a[k]; );
+
+ if (k < high) {
+ continue;
+ }
+ }
+
+ if (count == 0 || a[last - 1] > a[last]) {
+ ++count;
+ }
+ run[count] = (last = k);
+ }
+
+ if (count < max && count > 1) {
+ /*
+ * The array is highly structured, therefore merge all runs.
+ */
+ merge(a, new double[length], true, parallel, low, run, 0, count);
+ }
+ return count < max;
+ }
+
+ /**
+ * Merges the specified runs.
+ *
+ * @param a the source array
+ * @param b the temporary buffer
+ * @param src specifies the type of the target: source or buffer
+ * @param parallel indicates whether merging is performed in parallel
+ * @param offset the start index of the source, inclusive
+ * @param run the start indexes of the runs, inclusive
+ * @param lo the start index of the first run, inclusive
+ * @param hi the start index of the last run, inclusive
+ * @return the target where runs are merged
+ */
+ private static double[] merge(double[] a, double[] b, boolean src,
+ boolean parallel, int offset, int[] run, int lo, int hi) {
+
+ if (hi - lo == 1) {
+ if (src) {
+ return a;
+ }
+ for (int i = run[hi], j = i - offset, low = run[lo]; i > low;
+ b[--j] = a[--i]
+ );
+ return b;
+ }
+ int mi = (lo + hi) >>> 1;
+
+ double[] a1, a2; // the left and the right halves to be merged
+
+ if (parallel && hi - lo > MIN_PARALLEL_RUNS_COUNT) {
+ Merger merger1 = new Merger(a, b, !src, offset, run, lo, mi);
+ Merger merger2 = new Merger(a, b, true, offset, run, mi, hi);
+
+ ForkJoinTask.invokeAll(merger1, merger2);
+
+ a1 = merger1.getRawResult();
+ a2 = merger2.getRawResult();
+ } else {
+ a1 = merge(a, b, !src, false, offset, run, lo, mi);
+ a2 = merge(a, b, true, false, offset, run, mi, hi);
+ }
+ return merge(
+ a1 == a ? b : a,
+ a1 == a ? run[lo] - offset : run[lo],
+ a1,
+ a1 == b ? run[lo] - offset : run[lo],
+ a1 == b ? run[mi] - offset : run[mi],
+ a2,
+ a2 == b ? run[mi] - offset : run[mi],
+ a2 == b ? run[hi] - offset : run[hi]);
+ }
+
+ /**
+ * Merges the sorted halves.
+ *
+ * @param dst the destination where halves are merged
+ * @param k the start index of the destination, inclusive
+ * @param a1 the first half
+ * @param i the start index of the first half, inclusive
+ * @param hi the end index of the first half, exclusive
+ * @param a2 the second half
+ * @param j the start index of the second half, inclusive
+ * @param hj the end index of the second half, exclusive
+ * @return the merged halves
+ */
+ private static double[] merge(double[] dst, int k,
+ double[] a1, int i, int hi, double[] a2, int j, int hj) {
+
+ while (true) {
+ dst[k++] = a1[i] < a2[j] ? a1[i++] : a2[j++];
+
+ if (i == hi) {
+ while (j < hj) {
+ dst[k++] = a2[j++];
+ }
+ return dst;
+ }
+ if (j == hj) {
+ while (i < hi) {
+ dst[k++] = a1[i++];
+ }
+ return dst;
+ }
+ }
+ }
+
+ /**
+ * Sorts the specified range of the array by the nano insertion sort.
+ *
+ * @param a the array to be sorted
+ * @param low the index of the first element, inclusive, to be sorted
+ * @param high the index of the last element, exclusive, to be sorted
+ */
+ static void nanoInsertionSort(int[] a, int low, int high) {
+ /*
+ * In the context of Quicksort, the elements from the left part
+ * play the role of sentinels. Therefore expensive check of the
+ * left range on each iteration can be skipped.
+ */
+ for (int k; ++low < high; ) {
+ int ak = a[k = low];
+
+ while (ak < a[--k]) {
+ a[k + 1] = a[k];
+ }
+ a[k + 1] = ak;
+ }
+ }
+
+ /**
+ * Sorts the specified range of the array by the nano insertion sort.
+ *
+ * @param a the array to be sorted
+ * @param low the index of the first element, inclusive, to be sorted
+ * @param high the index of the last element, exclusive, to be sorted
+ */
+ static void nanoInsertionSort(long[] a, int low, int high) {
+ /*
+ * In the context of Quicksort, the elements from the left part
+ * play the role of sentinels. Therefore expensive check of the
+ * left range on each iteration can be skipped.
+ */
+ for (int k; ++low < high; ) {
+ long ak = a[k = low];
+
+ while (ak < a[--k]) {
+ a[k + 1] = a[k];
+ }
+ a[k + 1] = ak;
+ }
+ }
+
+ /**
+ * Sorts the specified range of the array by the nano insertion sort.
+ *
+ * @param a the array to be sorted
+ * @param low the index of the first element, inclusive, to be sorted
+ * @param high the index of the last element, exclusive, to be sorted
+ */
+ static void nanoInsertionSort(char[] a, int low, int high) {
+ /*
+ * In the context of Quicksort, the elements from the left part
+ * play the role of sentinels. Therefore expensive check of the
+ * left range on each iteration can be skipped.
+ */
+ for (int k; ++low < high; ) {
+ char ak = a[k = low];
+
+ while (ak < a[--k]) {
+ a[k + 1] = a[k];
+ }
+ a[k + 1] = ak;
+ }
+ }
+
+ /**
+ * Sorts the specified range of the array by the nano insertion sort.
+ *
+ * @param a the array to be sorted
+ * @param low the index of the first element, inclusive, to be sorted
+ * @param high the index of the last element, exclusive, to be sorted
+ */
+ static void nanoInsertionSort(short[] a, int low, int high) {
+ /*
+ * In the context of Quicksort, the elements from the left part
+ * play the role of sentinels. Therefore expensive check of the
+ * left range on each iteration can be skipped.
+ */
+ for (int k; ++low < high; ) {
+ short ak = a[k = low];
+
+ while (ak < a[--k]) {
+ a[k + 1] = a[k];
+ }
+ a[k + 1] = ak;
+ }
+ }
+
+ /**
+ * Sorts the specified range of the array by the nano insertion sort.
+ *
+ * @param a the array to be sorted
+ * @param low the index of the first element, inclusive, to be sorted
+ * @param high the index of the last element, exclusive, to be sorted
+ */
+ static void nanoInsertionSort(float[] a, int low, int high) {
+ /*
+ * In the context of Quicksort, the elements from the left part
+ * play the role of sentinels. Therefore expensive check of the
+ * left range on each iteration can be skipped.
+ */
+ for (int k; ++low < high; ) {
+ float ak = a[k = low];
+
+ while (ak < a[--k]) {
+ a[k + 1] = a[k];
+ }
+ a[k + 1] = ak;
+ }
+ }
+
+ /**
+ * Sorts the specified range of the array by the nano insertion sort.
+ *
+ * @param a the array to be sorted
+ * @param low the index of the first element, inclusive, to be sorted
+ * @param high the index of the last element, exclusive, to be sorted
+ */
+ static void nanoInsertionSort(double[] a, int low, int high) {
+ /*
+ * In the context of Quicksort, the elements from the left part
+ * play the role of sentinels. Therefore expensive check of the
+ * left range on each iteration can be skipped.
+ */
+ for (int k; ++low < high; ) {
+ double ak = a[k = low];
+
+ while (ak < a[--k]) {
+ a[k + 1] = a[k];
+ }
+ a[k + 1] = ak;
+ }
+ }
+
+ /**
+ * Sorts the specified range of the array by the pair insertion 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
+ */
+ static void pairInsertionSort(int[] a, int left, int right) {
+ /*
+ * Allign the left boundary.
+ */
+ left -= (left ^ right) & 1;
+
+ /*
+ * Two elements are inserted at once on each iteration.
+ * At first, we insert the greater element (a2) and then
+ * insert the less element (a1), but from position where
+ * the greater element was inserted. In the context of a
+ * Dual-Pivot Quicksort, the elements from the left part
+ * play the role of sentinels. Therefore expensive check
+ * of the left range on each iteration can be skipped.
+ */
+ for (int k; ++left < right; ) {
+ int a1 = a[k = ++left];
+
+ if (a[k - 2] > a[k - 1]) {
+ int a2 = a[--k];
+
+ if (a1 > a2) {
+ a2 = a1; a1 = a[k];
+ }
+ while (a2 < a[--k]) {
+ a[k + 2] = a[k];
+ }
+ a[++k + 1] = a2;
+ }
+ while (a1 < a[--k]) {
+ a[k + 1] = a[k];
+ }
+ a[k + 1] = a1;
+ }
+ }
+
+ /**
+ * Sorts the specified range of the array by the pair insertion 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
+ */
+ static void pairInsertionSort(long[] a, int left, int right) {
+ /*
+ * Allign the left boundary.
+ */
+ left -= (left ^ right) & 1;
+
+ /*
+ * Two elements are inserted at once on each iteration.
+ * At first, we insert the greater element (a2) and then
+ * insert the less element (a1), but from position where
+ * the greater element was inserted. In the context of a
+ * Dual-Pivot Quicksort, the elements from the left part
+ * play the role of sentinels. Therefore expensive check
+ * of the left range on each iteration can be skipped.
+ */
+ for (int k; ++left < right; ) {
+ long a1 = a[k = ++left];
+
+ if (a[k - 2] > a[k - 1]) {
+ long a2 = a[--k];
+
+ if (a1 > a2) {
+ a2 = a1; a1 = a[k];
+ }
+ while (a2 < a[--k]) {
+ a[k + 2] = a[k];
+ }
+ a[++k + 1] = a2;
+ }
+ while (a1 < a[--k]) {
+ a[k + 1] = a[k];
+ }
+ a[k + 1] = a1;
+ }
+ }
+
+ /**
+ * Sorts the specified range of the array by the pair insertion 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
+ */
+ static void pairInsertionSort(char[] a, int left, int right) {
+ /*
+ * Allign the left boundary.
+ */
+ left -= (left ^ right) & 1;
+
+ /*
+ * Two elements are inserted at once on each iteration.
+ * At first, we insert the greater element (a2) and then
+ * insert the less element (a1), but from position where
+ * the greater element was inserted. In the context of a
+ * Dual-Pivot Quicksort, the elements from the left part
+ * play the role of sentinels. Therefore expensive check
+ * of the left range on each iteration can be skipped.
+ */
+ for (int k; ++left < right; ) {
+ char a1 = a[k = ++left];
+
+ if (a[k - 2] > a[k - 1]) {
+ char a2 = a[--k];
+
+ if (a1 > a2) {
+ a2 = a1; a1 = a[k];
+ }
+ while (a2 < a[--k]) {
+ a[k + 2] = a[k];
+ }
+ a[++k + 1] = a2;
+ }
+ while (a1 < a[--k]) {
+ a[k + 1] = a[k];
+ }
+ a[k + 1] = a1;
+ }
+ }
+
+ /**
+ * Sorts the specified range of the array by the pair insertion 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
+ */
+ static void pairInsertionSort(short[] a, int left, int right) {
+ /*
+ * Allign the left boundary.
+ */
+ left -= (left ^ right) & 1;
+
+ /*
+ * Two elements are inserted at once on each iteration.
+ * At first, we insert the greater element (a2) and then
+ * insert the less element (a1), but from position where
+ * the greater element was inserted. In the context of a
+ * Dual-Pivot Quicksort, the elements from the left part
+ * play the role of sentinels. Therefore expensive check
+ * of the left range on each iteration can be skipped.
+ */
+ for (int k; ++left < right; ) {
+ short a1 = a[k = ++left];
+
+ if (a[k - 2] > a[k - 1]) {
+ short a2 = a[--k];
+
+ if (a1 > a2) {
+ a2 = a1; a1 = a[k];
+ }
+ while (a2 < a[--k]) {
+ a[k + 2] = a[k];
+ }
+ a[++k + 1] = a2;
+ }
+ while (a1 < a[--k]) {
+ a[k + 1] = a[k];
+ }
+ a[k + 1] = a1;
+ }
+ }
+
+ /**
+ * Sorts the specified range of the array by the pair insertion 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
+ */
+ static void pairInsertionSort(float[] a, int left, int right) {
+ /*
+ * Allign the left boundary.
+ */
+ left -= (left ^ right) & 1;
+
+ /*
+ * Two elements are inserted at once on each iteration.
+ * At first, we insert the greater element (a2) and then
+ * insert the less element (a1), but from position where
+ * the greater element was inserted. In the context of a
+ * Dual-Pivot Quicksort, the elements from the left part
+ * play the role of sentinels. Therefore expensive check
+ * of the left range on each iteration can be skipped.
+ */
+ for (int k; ++left < right; ) {
+ float a1 = a[k = ++left];
+
+ if (a[k - 2] > a[k - 1]) {
+ float a2 = a[--k];
+
+ if (a1 > a2) {
+ a2 = a1; a1 = a[k];
+ }
+ while (a2 < a[--k]) {
+ a[k + 2] = a[k];
+ }
+ a[++k + 1] = a2;
+ }
+ while (a1 < a[--k]) {
+ a[k + 1] = a[k];
+ }
+ a[k + 1] = a1;
+ }
+ }
+
+ /**
+ * Sorts the specified range of the array by the pair insertion 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
+ */
+ static void pairInsertionSort(double[] a, int left, int right) {
+ /*
+ * Allign the left boundary.
+ */
+ left -= (left ^ right) & 1;
+
+ /*
+ * Two elements are inserted at once on each iteration.
+ * At first, we insert the greater element (a2) and then
+ * insert the less element (a1), but from position where
+ * the greater element was inserted. In the context of a
+ * Dual-Pivot Quicksort, the elements from the left part
+ * play the role of sentinels. Therefore expensive check
+ * of the left range on each iteration can be skipped.
+ */
+ for (int k; ++left < right; ) {
+ double a1 = a[k = ++left];
+
+ if (a[k - 2] > a[k - 1]) {
+ double a2 = a[--k];
+
+ if (a1 > a2) {
+ a2 = a1; a1 = a[k];
+ }
+ while (a2 < a[--k]) {
+ a[k + 2] = a[k];
+ }
+ a[++k + 1] = a2;
+ }
+ while (a1 < a[--k]) {
+ a[k + 1] = a[k];
+ }
+ a[k + 1] = a1;
+ }
+ }
+
+ /**
+ * Sorts the specified range of the array by optimized insertion sort.
+ *
+ * @param a the array to be sorted
+ * @param low the index of the first element, inclusive, to be sorted
+ * @param high the index of the last element, exclusive, to be sorted
+ */
+ static void insertionSort(byte[] a, int low, int high) {
+ for (int i, k = low; ++k < high; ) {
+ byte ak = a[i = k];
+
+ if (ak < a[low]) {
+ a[i] = a[low]; a[low] = ak; ak = a[i];
+ }
+ while (ak < a[--i]) {
+ a[i + 1] = a[i];
+ }
+ a[i + 1] = ak;
+ }
+ }
+
+ /**
+ * The number of distinct byte values.
+ */
+ private static final int NUM_BYTE_VALUES = 1 << 8;
+
+ /**
+ * Sorts the specified range of the array by the counting sort.
+ *
+ * @param a the array to be sorted
+ * @param low the index of the first element, inclusive, to be sorted
+ * @param high the index of the last element, exclusive, to be sorted
+ */
+ static void countingSort(byte[] a, int low, int high) {
+ int[] count = new int[NUM_BYTE_VALUES];
+
+ /*
+ * Compute a histogram with the number of each values.
+ */
+ for (int i = low; i < high; ++i) {
+ ++count[a[i] - Byte.MIN_VALUE];
+ }
+
+ /*
+ * Place values on their final positions.
+ */
+ for (int i = NUM_BYTE_VALUES, k = high; k > low; ) {
+ while (count[--i] == 0);
+ byte value = (byte) (i + Byte.MIN_VALUE);
+ for (int j = count[i]; --j >= 0; a[--k] = value);
+ }
+ }
+
+ /**
+ * The number of distinct char values.
+ */
+ private static final int NUM_CHAR_VALUES = 1 << 16;
+
+ /**
+ * Sorts the specified range of the array by the counting sort.
+ *
+ * @param a the array to be sorted
+ * @param low the index of the first element, inclusive, to be sorted
+ * @param high the index of the last element, exclusive, to be sorted
+ */
+ static void countingSort(char[] a, int low, int high) {
+ int[] count = new int[NUM_CHAR_VALUES];
+
+ /*
+ * Compute a histogram with the number of each values.
+ */
+ for (int i = low; i < high; ++i) {
+ ++count[a[i]];
+ }
+
+ /*
+ * Place values on their final positions.
+ */
+ for (int i = NUM_CHAR_VALUES, k = high; k > low; ) {
+ while (count[--i] == 0);
+ char value = (char) i;
+ for (int j = count[i]; --j >= 0; a[--k] = value);
+ }
+ }
+
+ /**
+ * The number of distinct short values.
+ */
+ private static final int NUM_SHORT_VALUES = 1 << 16;
+
+ /**
+ * Sorts the specified range of the array by the counting sort.
+ *
+ * @param a the array to be sorted
+ * @param low the index of the first element, inclusive, to be sorted
+ * @param high the index of the last element, exclusive, to be sorted
+ */
+ static void countingSort(short[] a, int low, int high) {
+ int[] count = new int[NUM_SHORT_VALUES];
+
+ /*
+ * Compute a histogram with the number of each values.
+ */
+ for (int i = low; i < high; ++i) {
+ ++count[a[i] - Short.MIN_VALUE];
+ }
+
+ /*
+ * Place values on their final positions.
+ */
+ for (int i = NUM_SHORT_VALUES, k = high; k > low; ) {
+ while (count[--i] == 0);
+ short value = (short) (i + Short.MIN_VALUE);
+ for (int j = count[i]; --j >= 0; a[--k] = value);
+ }
+ }
+
+ /**
+ * Sorts the specified range of the array by the heap 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
+ */
+ static void heapSort(int[] a, int left, int right) {
+ for (int k = (left + 1 + right) >>> 1; k > left; ) {
+ pushDown(a, --k, a[k], left, right);
+ }
+ for (int k = right; k > left; --k) {
+ int max = a[left];
+ pushDown(a, left, a[k], left, k);
+ a[k] = max;
+ }
+ }
+
+ /**
+ * Pushes specified element down during the heap sort.
+ *
+ * @param a the given array
+ * @param p the start index
+ * @param value the given element
+ * @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 pushDown(int[] a, int p, int value, int left, int right) {
+ for (int k ;; a[p] = a[p = k]) {
+ k = (p << 1) - left + 2; // the index of the right child
+
+ if (k > right || a[k - 1] > a[k]) {
+ --k;
+ }
+ if (k > right || a[k] <= value) {
+ a[p] = value;
+ return;
+ }
+ }
+ }
+
+ /**
+ * Sorts the specified range of the array by the heap 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
+ */
+ static void heapSort(long[] a, int left, int right) {
+ for (int k = (left + 1 + right) >>> 1; k > left; ) {
+ pushDown(a, --k, a[k], left, right);
+ }
+ for (int k = right; k > left; --k) {
+ long max = a[left];
+ pushDown(a, left, a[k], left, k);
+ a[k] = max;
+ }
+ }
+
+ /**
+ * Pushes specified element down during the heap sort.
+ *
+ * @param a the given array
+ * @param p the start index
+ * @param value the given element
+ * @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 pushDown(long[] a, int p, long value, int left, int right) {
+ for (int k ;; a[p] = a[p = k]) {
+ k = (p << 1) - left + 2; // the index of the right child
+
+ if (k > right || a[k - 1] > a[k]) {
+ --k;
+ }
+ if (k > right || a[k] <= value) {
+ a[p] = value;
+ return;
+ }
+ }
+ }
+
+ /**
+ * Sorts the specified range of the array by the heap 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
+ */
+ static void heapSort(char[] a, int left, int right) {
+ for (int k = (left + 1 + right) >>> 1; k > left; ) {
+ pushDown(a, --k, a[k], left, right);
+ }
+ for (int k = right; k > left; --k) {
+ char max = a[left];
+ pushDown(a, left, a[k], left, k);
+ a[k] = max;
+ }
+ }
+
+ /**
+ * Pushes specified element down during the heap sort.
+ *
+ * @param a the given array
+ * @param p the start index
+ * @param value the given element
+ * @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 pushDown(char[] a, int p, char value, int left, int right) {
+ for (int k ;; a[p] = a[p = k]) {
+ k = (p << 1) - left + 2; // the index of the right child
+
+ if (k > right || a[k - 1] > a[k]) {
+ --k;
+ }
+ if (k > right || a[k] <= value) {
+ a[p] = value;
+ return;
+ }
+ }
+ }
+
+ /**
+ * Sorts the specified range of the array by the heap 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
+ */
+ static void heapSort(short[] a, int left, int right) {
+ for (int k = (left + 1 + right) >>> 1; k > left; ) {
+ pushDown(a, --k, a[k], left, right);
+ }
+ for (int k = right; k > left; --k) {
+ short max = a[left];
+ pushDown(a, left, a[k], left, k);
+ a[k] = max;
+ }
+ }
+
+ /**
+ * Pushes specified element down during the heap sort.
+ *
+ * @param a the given array
+ * @param p the start index
+ * @param value the given element
+ * @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 pushDown(short[] a, int p, short value, int left, int right) {
+ for (int k ;; a[p] = a[p = k]) {
+ k = (p << 1) - left + 2; // the index of the right child
+
+ if (k > right || a[k - 1] > a[k]) {
+ --k;
+ }
+ if (k > right || a[k] <= value) {
+ a[p] = value;
+ return;
+ }
+ }
+ }
+
+ /**
+ * Sorts the specified range of the array by the heap 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
+ */
+ static void heapSort(float[] a, int left, int right) {
+ for (int k = (left + 1 + right) >>> 1; k > left; ) {
+ pushDown(a, --k, a[k], left, right);
+ }
+ for (int k = right; k > left; --k) {
+ float max = a[left];
+ pushDown(a, left, a[k], left, k);
+ a[k] = max;
+ }
+ }
+
+ /**
+ * Pushes specified element down during the heap sort.
+ *
+ * @param a the given array
+ * @param p the start index
+ * @param value the given element
+ * @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 pushDown(float[] a, int p, float value, int left, int right) {
+ for (int k ;; a[p] = a[p = k]) {
+ k = (p << 1) - left + 2; // the index of the right child
+
+ if (k > right || a[k - 1] > a[k]) {
+ --k;
+ }
+ if (k > right || a[k] <= value) {
+ a[p] = value;
+ return;
+ }
+ }
+ }
+
+ /**
+ * Sorts the specified range of the array by the heap 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
+ */
+ static void heapSort(double[] a, int left, int right) {
+ for (int k = (left + 1 + right) >>> 1; k > left; ) {
+ pushDown(a, --k, a[k], left, right);
+ }
+ for (int k = right; k > left; --k) {
+ double max = a[left];
+ pushDown(a, left, a[k], left, k);
+ a[k] = max;
+ }
+ }
+
+ /**
+ * Pushes specified element down during the heap sort.
+ *
+ * @param a the given array
+ * @param p the start index
+ * @param value the given element
+ * @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 pushDown(double[] a, int p, double value, int left, int right) {
+ for (int k ;; a[p] = a[p = k]) {
+ k = (p << 1) - left + 2; // the index of the right child
+
+ if (k > right || a[k - 1] > a[k]) {
+ --k;
+ }
+ if (k > right || a[k] <= value) {
+ a[p] = value;
+ return;
+ }
+ }
+ }
+}