mirror of
https://gitlab.uni-marburg.de/langbeid/powersort.git
synced 2025-01-22 19:55:44 +01:00
adjust QuickSort
This commit is contained in:
parent
438d0099da
commit
fe7fe86dee
@ -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,7 +100,7 @@ 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.
|
||||||
*
|
*
|
||||||
@ -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
|
||||||
* @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
|
* the array to sort, otherwise if the array is {@code null},an absolute
|
||||||
* address pointing to the first element to sort from.
|
* address pointing to the first element to sort from.
|
||||||
* @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
|
||||||
* @param so the method reference for the fallback implementation
|
* @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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,25 +146,20 @@ 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 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 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,
|
||||||
@ -181,8 +171,6 @@ public final class DualPivotQuicksort {
|
|||||||
* @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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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];
|
||||||
|
|
||||||
@ -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];
|
||||||
/*
|
/*
|
||||||
@ -338,7 +352,6 @@ public final class DualPivotQuicksort {
|
|||||||
* @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,10 +423,12 @@ 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};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -424,7 +439,6 @@ public final class DualPivotQuicksort {
|
|||||||
* @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,16 +498,17 @@ 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,
|
||||||
@ -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.
|
||||||
@ -660,7 +675,7 @@ public final class DualPivotQuicksort {
|
|||||||
* @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) {
|
||||||
@ -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,7 +801,8 @@ 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);
|
||||||
@ -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,7 +840,7 @@ 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.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user