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 */