adjust QuickSort

This commit is contained in:
Daniel Langbein 2024-12-17 20:28:46 +00:00
parent 438d0099da
commit fe7fe86dee
Signed by: langfingaz
GPG Key ID: 6C47C753F0823002

View File

@ -28,8 +28,6 @@ package de.uni_marburg.powersort.sort.dpqs;
*/ */
import java.util.Arrays; import java.util.Arrays;
import java.util.concurrent.CountedCompleter;
import java.util.concurrent.RecursiveTask;
/** /**
* This class implements powerful and fully optimized versions, both * This class implements powerful and fully optimized versions, both
@ -37,7 +35,7 @@ import java.util.concurrent.RecursiveTask;
* Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm
* offers O(n log(n)) performance on all data sets, and is typically * offers O(n log(n)) performance on all data sets, and is typically
* faster than traditional (one-pivot) Quicksort implementations. * faster than traditional (one-pivot) Quicksort implementations.
* * <p>
* There are also additional algorithms, invoked from the Dual-Pivot * There are also additional algorithms, invoked from the Dual-Pivot
* Quicksort, such as mixed insertion sort, merging of runs and heap * Quicksort, such as mixed insertion sort, merging of runs and heap
* sort, counting sort and parallel merge sort. * sort, counting sort and parallel merge sort.
@ -46,9 +44,7 @@ import java.util.concurrent.RecursiveTask;
* @author Jon Bentley * @author Jon Bentley
* @author Josh Bloch * @author Josh Bloch
* @author Doug Lea * @author Doug Lea
*
* @version 2018.08.18 * @version 2018.08.18
*
* @since 1.7 * 14 * @since 1.7 * 14
*/ */
public final class DualPivotQuicksort { public final class DualPivotQuicksort {
@ -56,7 +52,8 @@ public final class DualPivotQuicksort {
/** /**
* Prevents instantiation. * Prevents instantiation.
*/ */
private DualPivotQuicksort() {} private DualPivotQuicksort() {
}
/** /**
* Max array size to use mixed insertion sort. * Max array size to use mixed insertion sort.
@ -103,12 +100,12 @@ public final class DualPivotQuicksort {
* of the array into ascending order. * of the array into ascending order.
*/ */
@FunctionalInterface @FunctionalInterface
private static interface SortOperation<A> { private interface SortOperation<A> {
/** /**
* Sorts the specified range of the array. * Sorts the specified range of the array.
* *
* @param a the array to be sorted * @param a the array to be sorted
* @param low the index of the first element, inclusive, 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 * @param high the index of the last element, exclusive, to be sorted
*/ */
void sort(A a, int low, int high); void sort(A a, int low, int high);
@ -117,16 +114,14 @@ public final class DualPivotQuicksort {
/** /**
* Sorts the specified range of the array into ascending numerical order. * Sorts the specified range of the array into ascending numerical order.
* *
* @param elemType the class of the elements of the array to be sorted * @param array the array to be sorted
* @param array the array to be sorted * the array to sort, otherwise if the array is {@code null},an absolute
* @param offset the relative offset, in bytes, from the base address of * address pointing to the first element to sort from.
* the array to sort, otherwise if the array is {@code null},an absolute * @param low the index of the first element, inclusive, to be sorted
* address pointing to the first element to sort from. * @param high the index of the last element, exclusive, to be sorted
* @param low the index of the first element, inclusive, to be sorted * @param so the method reference for the fallback implementation
* @param high the index of the last element, exclusive, to be sorted
* @param so the method reference for the fallback implementation
*/ */
private static <A> void sort(Class<?> elemType, A array, long offset, int low, int high, SortOperation<A> so) { private static <A> void sort(A array, int low, int high, SortOperation<A> so) {
so.sort(array, low, high); so.sort(array, low, high);
} }
@ -139,9 +134,9 @@ public final class DualPivotQuicksort {
/** /**
* Partitions the specified range of the array using the given pivots. * Partitions the specified range of the array using the given pivots.
* *
* @param a the array to be partitioned * @param a the array to be partitioned
* @param low the index of the first element, inclusive, to be partitioned * @param low the index of the first element, inclusive, to be partitioned
* @param high the index of the last element, exclusive, to be partitioned * @param high the index of the last element, exclusive, to be partitioned
* @param pivotIndex1 the index of pivot1, the first pivot * @param pivotIndex1 the index of pivot1, the first pivot
* @param pivotIndex2 the index of pivot2, the second pivot * @param pivotIndex2 the index of pivot2, the second pivot
*/ */
@ -151,49 +146,42 @@ public final class DualPivotQuicksort {
/** /**
* Partitions the specified range of the array using the two pivots provided. * Partitions the specified range of the array using the two pivots provided.
* *
* @param elemType the class of the array to be partitioned * @param array the array to be partitioned
* @param array the array to be partitioned * @param high the index of the last element, exclusive, to be partitioned
* @param offset the relative offset, in bytes, from the base address of
* the array to partition, otherwise if the array is {@code null},an absolute
* address pointing to the first element to partition from.
* @param low the index of the first element, inclusive, to be partitioned
* @param high the index of the last element, exclusive, to be partitioned
* @param pivotIndex1 the index of pivot1, the first pivot * @param pivotIndex1 the index of pivot1, the first pivot
* @param pivotIndex2 the index of pivot2, the second pivot * @param pivotIndex2 the index of pivot2, the second pivot
* @param po the method reference for the fallback implementation * @param po the method reference for the fallback implementation
*/ */
private static <A> int[] partition(Class<?> elemType, A array, long offset, int low, int high, int pivotIndex1, int pivotIndex2, PartitionOperation<A> po) { private static <A> int[] partition(A array, int high, int pivotIndex1, int pivotIndex2, PartitionOperation<A> po) {
return po.partition(array, low, high, pivotIndex1, pivotIndex2); return po.partition(array, Unsafe.ARRAY_INT_BASE_OFFSET, high, pivotIndex1, pivotIndex2);
} }
/** /**
* Sorts the specified range of the array using parallel merge * Sorts the specified range of the array using parallel merge
* sort and/or Dual-Pivot Quicksort. * sort and/or Dual-Pivot Quicksort.
* * <p>
* To balance the faster splitting and parallelism of merge sort * To balance the faster splitting and parallelism of merge sort
* with the faster element partitioning of Quicksort, ranges are * with the faster element partitioning of Quicksort, ranges are
* subdivided in tiers such that, if there is enough parallelism, * subdivided in tiers such that, if there is enough parallelism,
* the four-way parallel merge is started, still ensuring enough * the four-way parallel merge is started, still ensuring enough
* parallelism to process the partitions. * parallelism to process the partitions.
* *
* @param a the array to be sorted * @param a the array to be sorted
* @param low the index of the first element, inclusive, 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 * @param high the index of the last element, exclusive, to be sorted
*/ */
public static void sort(int[] a, int low, int high) { public static void sort(int[] a, int low, int high) {
int size = high - low; sort(a, 0, low, high);
sort(a, 0, low, high);
} }
/** /**
* Sorts the specified array using the Dual-Pivot Quicksort and/or * Sorts the specified array using the Dual-Pivot Quicksort and/or
* other sorts in special-cases, possibly with parallel partitions. * other sorts in special-cases, possibly with parallel partitions.
* *
* @param a the array to be sorted * @param a the array to be sorted
* @param bits the combination of recursion depth and bit flag, where * @param bits the combination of recursion depth and bit flag, where
* the right bit "0" indicates that array is the leftmost part * the right bit "0" indicates that array is the leftmost part
* @param low the index of the first element, inclusive, 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 * @param high the index of the last element, exclusive, to be sorted
*/ */
static void sort(int[] a, int bits, int low, int high) { static void sort(int[] a, int bits, int low, int high) {
@ -203,7 +191,7 @@ public final class DualPivotQuicksort {
* Run mixed insertion sort on small non-leftmost parts. * Run mixed insertion sort on small non-leftmost parts.
*/ */
if (size < MAX_MIXED_INSERTION_SORT_SIZE + bits && (bits & 1) > 0) { if (size < MAX_MIXED_INSERTION_SORT_SIZE + bits && (bits & 1) > 0) {
sort(int.class, a, Unsafe.ARRAY_INT_BASE_OFFSET, low, high, DualPivotQuicksort::mixedInsertionSort); sort(a, low, high, DualPivotQuicksort::mixedInsertionSort);
return; return;
} }
@ -211,7 +199,7 @@ public final class DualPivotQuicksort {
* Invoke insertion sort on small leftmost part. * Invoke insertion sort on small leftmost part.
*/ */
if (size < MAX_INSERTION_SORT_SIZE) { if (size < MAX_INSERTION_SORT_SIZE) {
sort(int.class, a, Unsafe.ARRAY_INT_BASE_OFFSET, low, high, DualPivotQuicksort::insertionSort); sort(a, low, high, DualPivotQuicksort::insertionSort);
return; return;
} }
@ -264,23 +252,49 @@ public final class DualPivotQuicksort {
* | | * | |
* 1 ------------o-----o------------ * 1 ------------o-----o------------
*/ */
if (a[e5] < a[e2]) { int t = a[e5]; a[e5] = a[e2]; a[e2] = t; } if (a[e5] < a[e2]) {
if (a[e4] < a[e1]) { int t = a[e4]; a[e4] = a[e1]; a[e1] = t; } int t = a[e5];
if (a[e5] < a[e4]) { int t = a[e5]; a[e5] = a[e4]; a[e4] = t; } a[e5] = a[e2];
if (a[e2] < a[e1]) { int t = a[e2]; a[e2] = a[e1]; a[e1] = t; } a[e2] = t;
if (a[e4] < a[e2]) { int t = a[e4]; a[e4] = a[e2]; a[e2] = t; } }
if (a[e4] < a[e1]) {
int t = a[e4];
a[e4] = a[e1];
a[e1] = t;
}
if (a[e5] < a[e4]) {
int t = a[e5];
a[e5] = a[e4];
a[e4] = t;
}
if (a[e2] < a[e1]) {
int t = a[e2];
a[e2] = a[e1];
a[e1] = t;
}
if (a[e4] < a[e2]) {
int t = a[e4];
a[e4] = a[e2];
a[e2] = t;
}
if (a3 < a[e2]) { if (a3 < a[e2]) {
if (a3 < a[e1]) { if (a3 < a[e1]) {
a[e3] = a[e2]; a[e2] = a[e1]; a[e1] = a3; a[e3] = a[e2];
a[e2] = a[e1];
a[e1] = a3;
} else { } else {
a[e3] = a[e2]; a[e2] = a3; a[e3] = a[e2];
a[e2] = a3;
} }
} else if (a3 > a[e4]) { } else if (a3 > a[e4]) {
if (a3 > a[e5]) { if (a3 > a[e5]) {
a[e3] = a[e4]; a[e4] = a[e5]; a[e5] = a3; a[e3] = a[e4];
a[e4] = a[e5];
a[e5] = a3;
} else { } else {
a[e3] = a[e4]; a[e4] = a3; a[e3] = a[e4];
a[e4] = a3;
} }
} }
@ -297,7 +311,7 @@ public final class DualPivotQuicksort {
* the pivots. These values are inexpensive approximation * the pivots. These values are inexpensive approximation
* of tertiles. Note, that pivot1 < pivot2. * of tertiles. Note, that pivot1 < pivot2.
*/ */
int[] pivotIndices = partition(int.class, a, Unsafe.ARRAY_INT_BASE_OFFSET, low, high, e1, e5, DualPivotQuicksort::partitionDualPivot); int[] pivotIndices = partition(a, high, e1, e5, DualPivotQuicksort::partitionDualPivot);
lower = pivotIndices[0]; lower = pivotIndices[0];
upper = pivotIndices[1]; upper = pivotIndices[1];
@ -307,8 +321,8 @@ public final class DualPivotQuicksort {
* Sort non-left parts recursively, * Sort non-left parts recursively,
* excluding known pivots. * excluding known pivots.
*/ */
sort(a, bits | 1, lower + 1, upper); sort(a, bits | 1, lower + 1, upper);
sort(a, bits | 1, upper + 1, high); sort(a, bits | 1, upper + 1, high);
} else { // Use single pivot in case of many equal elements } else { // Use single pivot in case of many equal elements
@ -316,7 +330,7 @@ public final class DualPivotQuicksort {
* Use the third of the five sorted elements as the pivot. * Use the third of the five sorted elements as the pivot.
* This value is inexpensive approximation of the median. * This value is inexpensive approximation of the median.
*/ */
int[] pivotIndices = partition(int.class, a, Unsafe.ARRAY_INT_BASE_OFFSET, low, high, e3, e3, DualPivotQuicksort::partitionSinglePivot); int[] pivotIndices = partition(a, high, e3, e3, DualPivotQuicksort::partitionSinglePivot);
lower = pivotIndices[0]; lower = pivotIndices[0];
upper = pivotIndices[1]; upper = pivotIndices[1];
/* /*
@ -324,7 +338,7 @@ public final class DualPivotQuicksort {
* known pivot. All elements from the central part are * known pivot. All elements from the central part are
* equal and therefore already sorted. * equal and therefore already sorted.
*/ */
sort(a, bits | 1, upper, high); sort(a, bits | 1, upper, high);
} }
high = lower; // Iterate along the left part high = lower; // Iterate along the left part
} }
@ -333,12 +347,11 @@ public final class DualPivotQuicksort {
/** /**
* Partitions the specified range of the array using the two pivots provided. * Partitions the specified range of the array using the two pivots provided.
* *
* @param a the array to be partitioned * @param a the array to be partitioned
* @param low the index of the first element, inclusive, for partitioning * @param low the index of the first element, inclusive, for partitioning
* @param high the index of the last element, exclusive, for partitioning * @param high the index of the last element, exclusive, for partitioning
* @param pivotIndex1 the index of pivot1, the first pivot * @param pivotIndex1 the index of pivot1, the first pivot
* @param pivotIndex2 the index of pivot2, the second pivot * @param pivotIndex2 the index of pivot2, the second pivot
*
*/ */
private static int[] partitionDualPivot(int[] a, int low, int high, int pivotIndex1, int pivotIndex2) { private static int[] partitionDualPivot(int[] a, int low, int high, int pivotIndex1, int pivotIndex2) {
int end = high - 1; int end = high - 1;
@ -363,8 +376,8 @@ public final class DualPivotQuicksort {
/* /*
* Skip elements, which are less or greater than the pivots. * Skip elements, which are less or greater than the pivots.
*/ */
while (a[++lower] < pivot1); while (a[++lower] < pivot1) ;
while (a[--upper] > pivot2); while (a[--upper] > pivot2) ;
/* /*
* Backward 3-interval partitioning * Backward 3-interval partitioning
@ -410,21 +423,22 @@ public final class DualPivotQuicksort {
/* /*
* Swap the pivots into their final positions. * Swap the pivots into their final positions.
*/ */
a[low] = a[lower]; a[lower] = pivot1; a[low] = a[lower];
a[end] = a[upper]; a[upper] = pivot2; a[lower] = pivot1;
a[end] = a[upper];
a[upper] = pivot2;
return new int[] {lower, upper}; return new int[]{lower, upper};
} }
/** /**
* Partitions the specified range of the array using a single pivot provided. * Partitions the specified range of the array using a single pivot provided.
* *
* @param a the array to be partitioned * @param a the array to be partitioned
* @param low the index of the first element, inclusive, for partitioning * @param low the index of the first element, inclusive, for partitioning
* @param high the index of the last element, exclusive, for partitioning * @param high the index of the last element, exclusive, for partitioning
* @param pivotIndex1 the index of pivot1, the first pivot * @param pivotIndex1 the index of pivot1, the first pivot
* @param pivotIndex2 the index of pivot2, the second pivot * @param pivotIndex2 the index of pivot2, the second pivot
*
*/ */
private static int[] partitionSinglePivot(int[] a, int low, int high, int pivotIndex1, int pivotIndex2) { private static int[] partitionSinglePivot(int[] a, int low, int high, int pivotIndex1, int pivotIndex2) {
@ -469,7 +483,7 @@ public final class DualPivotQuicksort {
a[k] = pivot; a[k] = pivot;
if (ak < pivot) { // Move a[k] to the left side if (ak < pivot) { // Move a[k] to the left side
while (a[++lower] < pivot); while (a[++lower] < pivot) ;
if (a[lower] > pivot) { if (a[lower] > pivot) {
a[--upper] = a[lower]; a[--upper] = a[lower];
@ -484,24 +498,25 @@ public final class DualPivotQuicksort {
/* /*
* Swap the pivot into its final position. * Swap the pivot into its final position.
*/ */
a[low] = a[lower]; a[lower] = pivot; a[low] = a[lower];
return new int[] {lower, upper}; a[lower] = pivot;
return new int[]{lower, upper};
} }
/** /**
* Sorts the specified range of the array using mixed insertion sort. * Sorts the specified range of the array using mixed insertion sort.
* * <p>
* Mixed insertion sort is combination of simple insertion sort, * Mixed insertion sort is combination of simple insertion sort,
* pin insertion sort and pair insertion sort. * pin insertion sort and pair insertion sort.
* * <p>
* In the context of Dual-Pivot Quicksort, the pivot element * In the context of Dual-Pivot Quicksort, the pivot element
* from the left part plays the role of sentinel, because it * from the left part plays the role of sentinel, because it
* is less than any elements from the given part. Therefore, * is less than any elements from the given part. Therefore,
* expensive check of the left range can be skipped on each * expensive check of the left range can be skipped on each
* iteration unless it is the leftmost call. * iteration unless it is the leftmost call.
* *
* @param a the array to be sorted * @param a the array to be sorted
* @param low the index of the first element, inclusive, 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 * @param high the index of the last element, exclusive, to be sorted
*/ */
private static void mixedInsertionSort(int[] a, int low, int high) { private static void mixedInsertionSort(int[] a, int low, int high) {
@ -553,7 +568,7 @@ public final class DualPivotQuicksort {
/* /*
* Find element smaller than pin. * Find element smaller than pin.
*/ */
while (a[--p] > pin); while (a[--p] > pin) ;
/* /*
* Swap it with large element. * Swap it with large element.
@ -615,8 +630,8 @@ public final class DualPivotQuicksort {
/** /**
* Sorts the specified range of the array using insertion sort. * Sorts the specified range of the array using insertion sort.
* *
* @param a the array to be sorted * @param a the array to be sorted
* @param low the index of the first element, inclusive, 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 * @param high the index of the last element, exclusive, to be sorted
*/ */
private static void insertionSort(int[] a, int low, int high) { private static void insertionSort(int[] a, int low, int high) {
@ -635,8 +650,8 @@ public final class DualPivotQuicksort {
/** /**
* Sorts the specified range of the array using heap sort. * Sorts the specified range of the array using heap sort.
* *
* @param a the array to be sorted * @param a the array to be sorted
* @param low the index of the first element, inclusive, 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 * @param high the index of the last element, exclusive, to be sorted
*/ */
private static void heapSort(int[] a, int low, int high) { private static void heapSort(int[] a, int low, int high) {
@ -653,14 +668,14 @@ public final class DualPivotQuicksort {
/** /**
* Pushes specified element down during heap sort. * Pushes specified element down during heap sort.
* *
* @param a the given array * @param a the given array
* @param p the start index * @param p the start index
* @param value the given element * @param value the given element
* @param low the index of the first element, inclusive, 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 * @param high the index of the last element, exclusive, to be sorted
*/ */
private static void pushDown(int[] a, int p, int value, int low, int high) { private static void pushDown(int[] a, int p, int value, int low, int high) {
for (int k ;; a[p] = a[p = k]) { for (int k; ; a[p] = a[p = k]) {
k = (p << 1) - low + 2; // Index of the right child k = (p << 1) - low + 2; // Index of the right child
if (k > high) { if (k > high) {
@ -679,8 +694,8 @@ public final class DualPivotQuicksort {
/** /**
* Tries to sort the specified range of the array. * Tries to sort the specified range of the array.
* *
* @param a the array to be sorted * @param a the array to be sorted
* @param low the index of the first element to be sorted * @param low the index of the first element to be sorted
* @param size the array size * @param size the array size
* @return true if finally sorted, false otherwise * @return true if finally sorted, false otherwise
*/ */
@ -706,19 +721,21 @@ public final class DualPivotQuicksort {
if (a[k - 1] < a[k]) { if (a[k - 1] < a[k]) {
// Identify ascending sequence // Identify ascending sequence
while (++k < high && a[k - 1] <= a[k]); while (++k < high && a[k - 1] <= a[k]) ;
} else if (a[k - 1] > a[k]) { } else if (a[k - 1] > a[k]) {
// Identify descending sequence // Identify descending sequence
while (++k < high && a[k - 1] >= a[k]); while (++k < high && a[k - 1] >= a[k]) ;
// Reverse into ascending order // Reverse into ascending order
for (int i = last - 1, j = k; ++i < --j && a[i] > a[j]; ) { for (int i = last - 1, j = k; ++i < --j && a[i] > a[j]; ) {
int ai = a[i]; a[i] = a[j]; a[j] = ai; int ai = a[i];
a[i] = a[j];
a[j] = ai;
} }
} else { // Identify constant sequence } else { // Identify constant sequence
for (int ak = a[k]; ++k < high && ak == a[k]; ); for (int ak = a[k]; ++k < high && ak == a[k]; ) ;
if (k < high) { if (k < high) {
continue; continue;
@ -784,9 +801,10 @@ public final class DualPivotQuicksort {
* Merge runs of highly structured array. * Merge runs of highly structured array.
*/ */
if (count > 1) { if (count > 1) {
int[] b; int offset = low; int[] b;
int offset = low;
b = new int[size]; b = new int[size];
mergeRuns(a, b, offset, 1, run, 0, count); mergeRuns(a, b, offset, 1, run, 0, count);
} }
return true; return true;
@ -795,13 +813,13 @@ public final class DualPivotQuicksort {
/** /**
* Merges the specified runs. * Merges the specified runs.
* *
* @param a the source array * @param a the source array
* @param b the temporary buffer used in merging * @param b the temporary buffer used in merging
* @param offset the start index in the source, inclusive * @param offset the start index in the source, inclusive
* @param aim specifies merging: to source ( > 0), buffer ( < 0) or any ( == 0) * @param aim specifies merging: to source ( > 0), buffer ( < 0) or any ( == 0)
* @param run the start indexes of the runs, inclusive * @param run the start indexes of the runs, inclusive
* @param lo the start index of the first run, inclusive * @param lo the start index of the first run, inclusive
* @param hi the start index of the last run, inclusive * @param hi the start index of the last run, inclusive
* @return the destination where runs are merged * @return the destination where runs are merged
*/ */
private static int[] mergeRuns(int[] a, int[] b, int offset, private static int[] mergeRuns(int[] a, int[] b, int offset,
@ -813,7 +831,8 @@ public final class DualPivotQuicksort {
} }
for (int i = run[hi], j = i - offset, low = run[lo]; i > low; for (int i = run[hi], j = i - offset, low = run[lo]; i > low;
b[--j] = a[--i] b[--j] = a[--i]
); )
;
return b; return b;
} }
@ -821,25 +840,25 @@ public final class DualPivotQuicksort {
* Split into approximately equal parts. * Split into approximately equal parts.
*/ */
int mi = lo, rmi = (run[lo] + run[hi]) >>> 1; int mi = lo, rmi = (run[lo] + run[hi]) >>> 1;
while (run[++mi + 1] <= rmi); while (run[++mi + 1] <= rmi) ;
/* /*
* Merge the left and right parts. * Merge the left and right parts.
*/ */
int[] a1, a2; int[] a1, a2;
a1 = mergeRuns(a, b, offset, -aim, run, lo, mi); a1 = mergeRuns(a, b, offset, -aim, run, lo, mi);
a2 = mergeRuns(a, b, offset, 0, run, mi, hi); a2 = mergeRuns(a, b, offset, 0, run, mi, hi);
int[] dst = a1 == a ? b : a; int[] dst = a1 == a ? b : a;
int k = a1 == a ? run[lo] - offset : run[lo]; int k = a1 == a ? run[lo] - offset : run[lo];
int lo1 = a1 == b ? run[lo] - offset : run[lo]; int lo1 = a1 == b ? run[lo] - offset : run[lo];
int hi1 = a1 == b ? run[mi] - offset : run[mi]; int hi1 = a1 == b ? run[mi] - offset : run[mi];
int lo2 = a2 == b ? run[mi] - offset : run[mi]; int lo2 = a2 == b ? run[mi] - offset : run[mi];
int hi2 = a2 == b ? run[hi] - offset : run[hi]; int hi2 = a2 == b ? run[hi] - offset : run[hi];
mergeParts(dst, k, a1, lo1, hi1, a2, lo2, hi2); mergeParts(dst, k, a1, lo1, hi1, a2, lo2, hi2);
return dst; return dst;
} }
@ -847,11 +866,11 @@ public final class DualPivotQuicksort {
* Merges the sorted parts. * Merges the sorted parts.
* *
* @param dst the destination where parts are merged * @param dst the destination where parts are merged
* @param k the start index of the destination, inclusive * @param k the start index of the destination, inclusive
* @param a1 the first part * @param a1 the first part
* @param lo1 the start index of the first part, inclusive * @param lo1 the start index of the first part, inclusive
* @param hi1 the end index of the first part, exclusive * @param hi1 the end index of the first part, exclusive
* @param a2 the second part * @param a2 the second part
* @param lo2 the start index of the second part, inclusive * @param lo2 the start index of the second part, inclusive
* @param hi2 the end index of the second part, exclusive * @param hi2 the end index of the second part, exclusive
*/ */