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