java.util.DualPivotQuicksort Maven / Gradle / Ivy
Show all versions of android-all Show documentation
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package java.util;
/**
* This class implements the Dual-Pivot Quicksort algorithm by
* Vladimir Yaroslavskiy, Jon Bentley, and Joshua 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
* faster than traditional (one-pivot) Quicksort implementations.
*
* @author Vladimir Yaroslavskiy
* @author Jon Bentley
* @author Josh Bloch
*
* @version 2009.11.29 m765.827.12i
*/
final class DualPivotQuicksort {
/**
* Prevents instantiation.
*/
private DualPivotQuicksort() {}
/*
* Tuning parameters.
*/
/**
* If the length of an array to be sorted is less than this
* constant, insertion sort is used in preference to Quicksort.
*/
private static final int INSERTION_SORT_THRESHOLD = 32;
/**
* If the length of a byte 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_BYTE = 128;
/**
* 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 = 32768;
/*
* Sorting methods for 7 primitive types.
*/
/**
* Sorts the specified array into ascending numerical order.
*
* @param a the array to be sorted
*/
public static void sort(int[] a) {
doSort(a, 0, a.length - 1);
}
/**
* Sorts the specified range of the array into ascending order. The range
* to be sorted extends from the index {@code fromIndex}, inclusive, to
* the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
* the range to be sorted is empty (and the call is a no-op).
*
* @param a the array to be sorted
* @param fromIndex the index of the first element, inclusive, to be sorted
* @param toIndex the index of the last element, exclusive, to be sorted
* @throws IllegalArgumentException if {@code fromIndex > toIndex}
* @throws ArrayIndexOutOfBoundsException
* if {@code fromIndex < 0} or {@code toIndex > a.length}
*/
public static void sort(int[] a, int fromIndex, int toIndex) {
Arrays.checkStartAndEnd(a.length, fromIndex, toIndex);
doSort(a, fromIndex, toIndex - 1);
}
/**
* Sorts the specified range of the array into ascending order. This
* method differs from the public {@code sort} method in that the
* {@code right} index is inclusive, and it does no range checking
* on {@code left} or {@code right}.
*
* @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
*/
private static void doSort(int[] a, int left, int right) {
// Use insertion sort on tiny arrays
if (right - left + 1 < INSERTION_SORT_THRESHOLD) {
for (int i = left + 1; i <= right; i++) {
int ai = a[i];
int j;
for (j = i - 1; j >= left && ai < a[j]; j--) {
a[j + 1] = a[j];
}
a[j + 1] = ai;
}
} else { // Use Dual-Pivot Quicksort on large arrays
dualPivotQuicksort(a, left, right);
}
}
/**
* Sorts the specified range of the array into ascending order by the
* Dual-Pivot Quicksort algorithm.
*
* @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
*/
private static void dualPivotQuicksort(int[] a, int left, int right) {
// Compute indices of five evenly spaced elements
int sixth = (right - left + 1) / 6;
int e1 = left + sixth;
int e5 = right - sixth;
int e3 = (left + right) >>> 1; // The midpoint
int e4 = e3 + sixth;
int e2 = e3 - sixth;
// Sort these elements using a 5-element sorting network
int ae1 = a[e1], ae2 = a[e2], ae3 = a[e3], ae4 = a[e4], ae5 = a[e5];
if (ae1 > ae2) { int t = ae1; ae1 = ae2; ae2 = t; }
if (ae4 > ae5) { int t = ae4; ae4 = ae5; ae5 = t; }
if (ae1 > ae3) { int t = ae1; ae1 = ae3; ae3 = t; }
if (ae2 > ae3) { int t = ae2; ae2 = ae3; ae3 = t; }
if (ae1 > ae4) { int t = ae1; ae1 = ae4; ae4 = t; }
if (ae3 > ae4) { int t = ae3; ae3 = ae4; ae4 = t; }
if (ae2 > ae5) { int t = ae2; ae2 = ae5; ae5 = t; }
if (ae2 > ae3) { int t = ae2; ae2 = ae3; ae3 = t; }
if (ae4 > ae5) { int t = ae4; ae4 = ae5; ae5 = t; }
a[e1] = ae1; a[e3] = ae3; a[e5] = ae5;
/*
* 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.
*
* The pivots are stored in local variables, and the first and
* the last of the 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 positions, and
* excluded from subsequent sorting.
*/
int pivot1 = ae2; a[e2] = a[left];
int pivot2 = ae4; a[e4] = a[right];
// Pointers
int less = left + 1; // The index of first element of center part
int great = right - 1; // The index before first element of right part
boolean pivotsDiffer = (pivot1 != pivot2);
if (pivotsDiffer) {
/*
* Partitioning:
*
* left part center part right part
* +------------------------------------------------------------+
* | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 |
* +------------------------------------------------------------+
* ^ ^ ^
* | | |
* less k great
*
* Invariants:
*
* all in (left, less) < pivot1
* pivot1 <= all in [less, k) <= pivot2
* all in (great, right) > pivot2
*
* Pointer k is the first index of ?-part
*/
outer:
for (int k = less; k <= great; k++) {
int ak = a[k];
if (ak < pivot1) { // Move a[k] to left part
if (k != less) {
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[k] = a[less];
a[less++] = a[great];
a[great--] = ak;
} else { // pivot1 <= a[great] <= pivot2
a[k] = a[great];
a[great--] = ak;
}
}
}
} else { // Pivots are equal
/*
* Partition degenerates to the traditional 3-way,
* or "Dutch National Flag", partition:
*
* left part center part right part
* +----------------------------------------------+
* | < pivot | == pivot | ? | > pivot |
* +----------------------------------------------+
* ^ ^ ^
* | | |
* less k great
*
* Invariants:
*
* all in (left, less) < pivot
* all in [less, k) == pivot
* all in (great, right) > pivot
*
* Pointer k is the first index of ?-part
*/
for (int k = less; k <= great; k++) {
int ak = a[k];
if (ak == pivot1) {
continue;
}
if (ak < pivot1) { // Move a[k] to left part
if (k != less) {
a[k] = a[less];
a[less] = ak;
}
less++;
} else { // (a[k] > pivot1) - Move a[k] to right part
/*
* We know that pivot1 == a[e3] == pivot2. Thus, we know
* that great will still be >= k when the following loop
* terminates, even though we don't test for it explicitly.
* In other words, a[e3] acts as a sentinel for great.
*/
while (a[great] > pivot1) {
great--;
}
if (a[great] < pivot1) {
a[k] = a[less];
a[less++] = a[great];
a[great--] = ak;
} else { // a[great] == pivot1
a[k] = pivot1;
a[great--] = ak;
}
}
}
}
// 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 pivot values
doSort(a, left, less - 2);
doSort(a, great + 2, right);
/*
* If pivot1 == pivot2, all elements from center
* part are equal and, therefore, already sorted
*/
if (!pivotsDiffer) {
return;
}
/*
* If center part is too large (comprises > 2/3 of the array),
* swap internal pivot values to ends
*/
if (less < e1 && great > e5) {
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; k <= great; k++) {
int ak = a[k];
if (ak == pivot2) { // Move a[k] to right part
while (a[great] == pivot2) {
if (great-- == k) {
break outer;
}
}
if (a[great] == pivot1) {
a[k] = a[less];
a[less++] = pivot1;
} else { // pivot1 < a[great] < pivot2
a[k] = a[great];
}
a[great--] = pivot2;
} else if (ak == pivot1) { // Move a[k] to left part
a[k] = a[less];
a[less++] = pivot1;
}
}
}
// Sort center part recursively, excluding known pivot values
doSort(a, less, great);
}
/**
* Sorts the specified array into ascending numerical order.
*
* @param a the array to be sorted
*/
public static void sort(long[] a) {
doSort(a, 0, a.length - 1);
}
/**
* Sorts the specified range of the array into ascending order. The range
* to be sorted extends from the index {@code fromIndex}, inclusive, to
* the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
* the range to be sorted is empty (and the call is a no-op).
*
* @param a the array to be sorted
* @param fromIndex the index of the first element, inclusive, to be sorted
* @param toIndex the index of the last element, exclusive, to be sorted
* @throws IllegalArgumentException if {@code fromIndex > toIndex}
* @throws ArrayIndexOutOfBoundsException
* if {@code fromIndex < 0} or {@code toIndex > a.length}
*/
public static void sort(long[] a, int fromIndex, int toIndex) {
Arrays.checkStartAndEnd(a.length, fromIndex, toIndex);
doSort(a, fromIndex, toIndex - 1);
}
/**
* Sorts the specified range of the array into ascending order. This
* method differs from the public {@code sort} method in that the
* {@code right} index is inclusive, and it does no range checking on
* {@code left} or {@code right}.
*
* @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
*/
private static void doSort(long[] a, int left, int right) {
// Use insertion sort on tiny arrays
if (right - left + 1 < INSERTION_SORT_THRESHOLD) {
for (int i = left + 1; i <= right; i++) {
long ai = a[i];
int j;
for (j = i - 1; j >= left && ai < a[j]; j--) {
a[j + 1] = a[j];
}
a[j + 1] = ai;
}
} else { // Use Dual-Pivot Quicksort on large arrays
dualPivotQuicksort(a, left, right);
}
}
/**
* Sorts the specified range of the array into ascending order by the
* Dual-Pivot Quicksort algorithm.
*
* @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
*/
private static void dualPivotQuicksort(long[] a, int left, int right) {
// Compute indices of five evenly spaced elements
int sixth = (right - left + 1) / 6;
int e1 = left + sixth;
int e5 = right - sixth;
int e3 = (left + right) >>> 1; // The midpoint
int e4 = e3 + sixth;
int e2 = e3 - sixth;
// Sort these elements using a 5-element sorting network
long ae1 = a[e1], ae2 = a[e2], ae3 = a[e3], ae4 = a[e4], ae5 = a[e5];
if (ae1 > ae2) { long t = ae1; ae1 = ae2; ae2 = t; }
if (ae4 > ae5) { long t = ae4; ae4 = ae5; ae5 = t; }
if (ae1 > ae3) { long t = ae1; ae1 = ae3; ae3 = t; }
if (ae2 > ae3) { long t = ae2; ae2 = ae3; ae3 = t; }
if (ae1 > ae4) { long t = ae1; ae1 = ae4; ae4 = t; }
if (ae3 > ae4) { long t = ae3; ae3 = ae4; ae4 = t; }
if (ae2 > ae5) { long t = ae2; ae2 = ae5; ae5 = t; }
if (ae2 > ae3) { long t = ae2; ae2 = ae3; ae3 = t; }
if (ae4 > ae5) { long t = ae4; ae4 = ae5; ae5 = t; }
a[e1] = ae1; a[e3] = ae3; a[e5] = ae5;
/*
* 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.
*
* The pivots are stored in local variables, and the first and
* the last of the 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 positions, and
* excluded from subsequent sorting.
*/
long pivot1 = ae2; a[e2] = a[left];
long pivot2 = ae4; a[e4] = a[right];
// Pointers
int less = left + 1; // The index of first element of center part
int great = right - 1; // The index before first element of right part
boolean pivotsDiffer = (pivot1 != pivot2);
if (pivotsDiffer) {
/*
* Partitioning:
*
* left part center part right part
* +------------------------------------------------------------+
* | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 |
* +------------------------------------------------------------+
* ^ ^ ^
* | | |
* less k great
*
* Invariants:
*
* all in (left, less) < pivot1
* pivot1 <= all in [less, k) <= pivot2
* all in (great, right) > pivot2
*
* Pointer k is the first index of ?-part
*/
outer:
for (int k = less; k <= great; k++) {
long ak = a[k];
if (ak < pivot1) { // Move a[k] to left part
if (k != less) {
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[k] = a[less];
a[less++] = a[great];
a[great--] = ak;
} else { // pivot1 <= a[great] <= pivot2
a[k] = a[great];
a[great--] = ak;
}
}
}
} else { // Pivots are equal
/*
* Partition degenerates to the traditional 3-way,
* or "Dutch National Flag", partition:
*
* left part center part right part
* +----------------------------------------------+
* | < pivot | == pivot | ? | > pivot |
* +----------------------------------------------+
* ^ ^ ^
* | | |
* less k great
*
* Invariants:
*
* all in (left, less) < pivot
* all in [less, k) == pivot
* all in (great, right) > pivot
*
* Pointer k is the first index of ?-part
*/
for (int k = less; k <= great; k++) {
long ak = a[k];
if (ak == pivot1) {
continue;
}
if (ak < pivot1) { // Move a[k] to left part
if (k != less) {
a[k] = a[less];
a[less] = ak;
}
less++;
} else { // (a[k] > pivot1) - Move a[k] to right part
/*
* We know that pivot1 == a[e3] == pivot2. Thus, we know
* that great will still be >= k when the following loop
* terminates, even though we don't test for it explicitly.
* In other words, a[e3] acts as a sentinel for great.
*/
while (a[great] > pivot1) {
great--;
}
if (a[great] < pivot1) {
a[k] = a[less];
a[less++] = a[great];
a[great--] = ak;
} else { // a[great] == pivot1
a[k] = pivot1;
a[great--] = ak;
}
}
}
}
// 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 pivot values
doSort(a, left, less - 2);
doSort(a, great + 2, right);
/*
* If pivot1 == pivot2, all elements from center
* part are equal and, therefore, already sorted
*/
if (!pivotsDiffer) {
return;
}
/*
* If center part is too large (comprises > 2/3 of the array),
* swap internal pivot values to ends
*/
if (less < e1 && great > e5) {
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; k <= great; k++) {
long ak = a[k];
if (ak == pivot2) { // Move a[k] to right part
while (a[great] == pivot2) {
if (great-- == k) {
break outer;
}
}
if (a[great] == pivot1) {
a[k] = a[less];
a[less++] = pivot1;
} else { // pivot1 < a[great] < pivot2
a[k] = a[great];
}
a[great--] = pivot2;
} else if (ak == pivot1) { // Move a[k] to left part
a[k] = a[less];
a[less++] = pivot1;
}
}
}
// Sort center part recursively, excluding known pivot values
doSort(a, less, great);
}
/**
* Sorts the specified array into ascending numerical order.
*
* @param a the array to be sorted
*/
public static void sort(short[] a) {
doSort(a, 0, a.length - 1);
}
/**
* Sorts the specified range of the array into ascending order. The range
* to be sorted extends from the index {@code fromIndex}, inclusive, to
* the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
* the range to be sorted is empty (and the call is a no-op).
*
* @param a the array to be sorted
* @param fromIndex the index of the first element, inclusive, to be sorted
* @param toIndex the index of the last element, exclusive, to be sorted
* @throws IllegalArgumentException if {@code fromIndex > toIndex}
* @throws ArrayIndexOutOfBoundsException
* if {@code fromIndex < 0} or {@code toIndex > a.length}
*/
public static void sort(short[] a, int fromIndex, int toIndex) {
Arrays.checkStartAndEnd(a.length, fromIndex, toIndex);
doSort(a, fromIndex, toIndex - 1);
}
/** The number of distinct short values. */
private static final int NUM_SHORT_VALUES = 1 << 16;
/**
* Sorts the specified range of the array into ascending order. This
* method differs from the public {@code sort} method in that the
* {@code right} index is inclusive, and it does no range checking on
* {@code left} or {@code right}.
*
* @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
*/
private static void doSort(short[] a, int left, int right) {
// Use insertion sort on tiny arrays
if (right - left + 1 < INSERTION_SORT_THRESHOLD) {
for (int i = left + 1; i <= right; i++) {
short ai = a[i];
int j;
for (j = i - 1; j >= left && ai < a[j]; j--) {
a[j + 1] = a[j];
}
a[j + 1] = ai;
}
} else if (right-left+1 > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) {
// Use counting sort on huge arrays
int[] count = new int[NUM_SHORT_VALUES];
for (int i = left; i <= right; i++) {
count[a[i] - Short.MIN_VALUE]++;
}
for (int i = 0, k = left; i < count.length && k <= right; i++) {
short value = (short) (i + Short.MIN_VALUE);
for (int s = count[i]; s > 0; s--) {
a[k++] = value;
}
}
} else { // Use Dual-Pivot Quicksort on large arrays
dualPivotQuicksort(a, left, right);
}
}
/**
* Sorts the specified range of the array into ascending order by the
* Dual-Pivot Quicksort algorithm.
*
* @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
*/
private static void dualPivotQuicksort(short[] a, int left, int right) {
// Compute indices of five evenly spaced elements
int sixth = (right - left + 1) / 6;
int e1 = left + sixth;
int e5 = right - sixth;
int e3 = (left + right) >>> 1; // The midpoint
int e4 = e3 + sixth;
int e2 = e3 - sixth;
// Sort these elements using a 5-element sorting network
short ae1 = a[e1], ae2 = a[e2], ae3 = a[e3], ae4 = a[e4], ae5 = a[e5];
if (ae1 > ae2) { short t = ae1; ae1 = ae2; ae2 = t; }
if (ae4 > ae5) { short t = ae4; ae4 = ae5; ae5 = t; }
if (ae1 > ae3) { short t = ae1; ae1 = ae3; ae3 = t; }
if (ae2 > ae3) { short t = ae2; ae2 = ae3; ae3 = t; }
if (ae1 > ae4) { short t = ae1; ae1 = ae4; ae4 = t; }
if (ae3 > ae4) { short t = ae3; ae3 = ae4; ae4 = t; }
if (ae2 > ae5) { short t = ae2; ae2 = ae5; ae5 = t; }
if (ae2 > ae3) { short t = ae2; ae2 = ae3; ae3 = t; }
if (ae4 > ae5) { short t = ae4; ae4 = ae5; ae5 = t; }
a[e1] = ae1; a[e3] = ae3; a[e5] = ae5;
/*
* 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.
*
* The pivots are stored in local variables, and the first and
* the last of the 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 positions, and
* excluded from subsequent sorting.
*/
short pivot1 = ae2; a[e2] = a[left];
short pivot2 = ae4; a[e4] = a[right];
// Pointers
int less = left + 1; // The index of first element of center part
int great = right - 1; // The index before first element of right part
boolean pivotsDiffer = (pivot1 != pivot2);
if (pivotsDiffer) {
/*
* Partitioning:
*
* left part center part right part
* +------------------------------------------------------------+
* | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 |
* +------------------------------------------------------------+
* ^ ^ ^
* | | |
* less k great
*
* Invariants:
*
* all in (left, less) < pivot1
* pivot1 <= all in [less, k) <= pivot2
* all in (great, right) > pivot2
*
* Pointer k is the first index of ?-part
*/
outer:
for (int k = less; k <= great; k++) {
short ak = a[k];
if (ak < pivot1) { // Move a[k] to left part
if (k != less) {
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[k] = a[less];
a[less++] = a[great];
a[great--] = ak;
} else { // pivot1 <= a[great] <= pivot2
a[k] = a[great];
a[great--] = ak;
}
}
}
} else { // Pivots are equal
/*
* Partition degenerates to the traditional 3-way,
* or "Dutch National Flag", partition:
*
* left part center part right part
* +----------------------------------------------+
* | < pivot | == pivot | ? | > pivot |
* +----------------------------------------------+
* ^ ^ ^
* | | |
* less k great
*
* Invariants:
*
* all in (left, less) < pivot
* all in [less, k) == pivot
* all in (great, right) > pivot
*
* Pointer k is the first index of ?-part
*/
for (int k = less; k <= great; k++) {
short ak = a[k];
if (ak == pivot1) {
continue;
}
if (ak < pivot1) { // Move a[k] to left part
if (k != less) {
a[k] = a[less];
a[less] = ak;
}
less++;
} else { // (a[k] > pivot1) - Move a[k] to right part
/*
* We know that pivot1 == a[e3] == pivot2. Thus, we know
* that great will still be >= k when the following loop
* terminates, even though we don't test for it explicitly.
* In other words, a[e3] acts as a sentinel for great.
*/
while (a[great] > pivot1) {
great--;
}
if (a[great] < pivot1) {
a[k] = a[less];
a[less++] = a[great];
a[great--] = ak;
} else { // a[great] == pivot1
a[k] = pivot1;
a[great--] = ak;
}
}
}
}
// 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 pivot values
doSort(a, left, less - 2);
doSort(a, great + 2, right);
/*
* If pivot1 == pivot2, all elements from center
* part are equal and, therefore, already sorted
*/
if (!pivotsDiffer) {
return;
}
/*
* If center part is too large (comprises > 2/3 of the array),
* swap internal pivot values to ends
*/
if (less < e1 && great > e5) {
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; k <= great; k++) {
short ak = a[k];
if (ak == pivot2) { // Move a[k] to right part
while (a[great] == pivot2) {
if (great-- == k) {
break outer;
}
}
if (a[great] == pivot1) {
a[k] = a[less];
a[less++] = pivot1;
} else { // pivot1 < a[great] < pivot2
a[k] = a[great];
}
a[great--] = pivot2;
} else if (ak == pivot1) { // Move a[k] to left part
a[k] = a[less];
a[less++] = pivot1;
}
}
}
// Sort center part recursively, excluding known pivot values
doSort(a, less, great);
}
/**
* Sorts the specified array into ascending numerical order.
*
* @param a the array to be sorted
*/
public static void sort(char[] a) {
doSort(a, 0, a.length - 1);
}
/**
* Sorts the specified range of the array into ascending order. The range
* to be sorted extends from the index {@code fromIndex}, inclusive, to
* the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
* the range to be sorted is empty (and the call is a no-op).
*
* @param a the array to be sorted
* @param fromIndex the index of the first element, inclusive, to be sorted
* @param toIndex the index of the last element, exclusive, to be sorted
* @throws IllegalArgumentException if {@code fromIndex > toIndex}
* @throws ArrayIndexOutOfBoundsException
* if {@code fromIndex < 0} or {@code toIndex > a.length}
*/
public static void sort(char[] a, int fromIndex, int toIndex) {
Arrays.checkStartAndEnd(a.length, fromIndex, toIndex);
doSort(a, fromIndex, toIndex - 1);
}
/** The number of distinct char values. */
private static final int NUM_CHAR_VALUES = 1 << 16;
/**
* Sorts the specified range of the array into ascending order. This
* method differs from the public {@code sort} method in that the
* {@code right} index is inclusive, and it does no range checking on
* {@code left} or {@code right}.
*
* @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
*/
private static void doSort(char[] a, int left, int right) {
// Use insertion sort on tiny arrays
if (right - left + 1 < INSERTION_SORT_THRESHOLD) {
for (int i = left + 1; i <= right; i++) {
char ai = a[i];
int j;
for (j = i - 1; j >= left && ai < a[j]; j--) {
a[j + 1] = a[j];
}
a[j + 1] = ai;
}
} else if (right-left+1 > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) {
// Use counting sort on huge arrays
int[] count = new int[NUM_CHAR_VALUES];
for (int i = left; i <= right; i++) {
count[a[i]]++;
}
for (int i = 0, k = left; i < count.length && k <= right; i++) {
for (int s = count[i]; s > 0; s--) {
a[k++] = (char) i;
}
}
} else { // Use Dual-Pivot Quicksort on large arrays
dualPivotQuicksort(a, left, right);
}
}
/**
* Sorts the specified range of the array into ascending order by the
* Dual-Pivot Quicksort algorithm.
*
* @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
*/
private static void dualPivotQuicksort(char[] a, int left, int right) {
// Compute indices of five evenly spaced elements
int sixth = (right - left + 1) / 6;
int e1 = left + sixth;
int e5 = right - sixth;
int e3 = (left + right) >>> 1; // The midpoint
int e4 = e3 + sixth;
int e2 = e3 - sixth;
// Sort these elements using a 5-element sorting network
char ae1 = a[e1], ae2 = a[e2], ae3 = a[e3], ae4 = a[e4], ae5 = a[e5];
if (ae1 > ae2) { char t = ae1; ae1 = ae2; ae2 = t; }
if (ae4 > ae5) { char t = ae4; ae4 = ae5; ae5 = t; }
if (ae1 > ae3) { char t = ae1; ae1 = ae3; ae3 = t; }
if (ae2 > ae3) { char t = ae2; ae2 = ae3; ae3 = t; }
if (ae1 > ae4) { char t = ae1; ae1 = ae4; ae4 = t; }
if (ae3 > ae4) { char t = ae3; ae3 = ae4; ae4 = t; }
if (ae2 > ae5) { char t = ae2; ae2 = ae5; ae5 = t; }
if (ae2 > ae3) { char t = ae2; ae2 = ae3; ae3 = t; }
if (ae4 > ae5) { char t = ae4; ae4 = ae5; ae5 = t; }
a[e1] = ae1; a[e3] = ae3; a[e5] = ae5;
/*
* 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.
*
* The pivots are stored in local variables, and the first and
* the last of the 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 positions, and
* excluded from subsequent sorting.
*/
char pivot1 = ae2; a[e2] = a[left];
char pivot2 = ae4; a[e4] = a[right];
// Pointers
int less = left + 1; // The index of first element of center part
int great = right - 1; // The index before first element of right part
boolean pivotsDiffer = (pivot1 != pivot2);
if (pivotsDiffer) {
/*
* Partitioning:
*
* left part center part right part
* +------------------------------------------------------------+
* | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 |
* +------------------------------------------------------------+
* ^ ^ ^
* | | |
* less k great
*
* Invariants:
*
* all in (left, less) < pivot1
* pivot1 <= all in [less, k) <= pivot2
* all in (great, right) > pivot2
*
* Pointer k is the first index of ?-part
*/
outer:
for (int k = less; k <= great; k++) {
char ak = a[k];
if (ak < pivot1) { // Move a[k] to left part
if (k != less) {
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[k] = a[less];
a[less++] = a[great];
a[great--] = ak;
} else { // pivot1 <= a[great] <= pivot2
a[k] = a[great];
a[great--] = ak;
}
}
}
} else { // Pivots are equal
/*
* Partition degenerates to the traditional 3-way,
* or "Dutch National Flag", partition:
*
* left part center part right part
* +----------------------------------------------+
* | < pivot | == pivot | ? | > pivot |
* +----------------------------------------------+
* ^ ^ ^
* | | |
* less k great
*
* Invariants:
*
* all in (left, less) < pivot
* all in [less, k) == pivot
* all in (great, right) > pivot
*
* Pointer k is the first index of ?-part
*/
for (int k = less; k <= great; k++) {
char ak = a[k];
if (ak == pivot1) {
continue;
}
if (ak < pivot1) { // Move a[k] to left part
if (k != less) {
a[k] = a[less];
a[less] = ak;
}
less++;
} else { // (a[k] > pivot1) - Move a[k] to right part
/*
* We know that pivot1 == a[e3] == pivot2. Thus, we know
* that great will still be >= k when the following loop
* terminates, even though we don't test for it explicitly.
* In other words, a[e3] acts as a sentinel for great.
*/
while (a[great] > pivot1) {
great--;
}
if (a[great] < pivot1) {
a[k] = a[less];
a[less++] = a[great];
a[great--] = ak;
} else { // a[great] == pivot1
a[k] = pivot1;
a[great--] = ak;
}
}
}
}
// 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 pivot values
doSort(a, left, less - 2);
doSort(a, great + 2, right);
/*
* If pivot1 == pivot2, all elements from center
* part are equal and, therefore, already sorted
*/
if (!pivotsDiffer) {
return;
}
/*
* If center part is too large (comprises > 2/3 of the array),
* swap internal pivot values to ends
*/
if (less < e1 && great > e5) {
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; k <= great; k++) {
char ak = a[k];
if (ak == pivot2) { // Move a[k] to right part
while (a[great] == pivot2) {
if (great-- == k) {
break outer;
}
}
if (a[great] == pivot1) {
a[k] = a[less];
a[less++] = pivot1;
} else { // pivot1 < a[great] < pivot2
a[k] = a[great];
}
a[great--] = pivot2;
} else if (ak == pivot1) { // Move a[k] to left part
a[k] = a[less];
a[less++] = pivot1;
}
}
}
// Sort center part recursively, excluding known pivot values
doSort(a, less, great);
}
/**
* Sorts the specified array into ascending numerical order.
*
* @param a the array to be sorted
*/
public static void sort(byte[] a) {
doSort(a, 0, a.length - 1);
}
/**
* Sorts the specified range of the array into ascending order. The range
* to be sorted extends from the index {@code fromIndex}, inclusive, to
* the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
* the range to be sorted is empty (and the call is a no-op).
*
* @param a the array to be sorted
* @param fromIndex the index of the first element, inclusive, to be sorted
* @param toIndex the index of the last element, exclusive, to be sorted
* @throws IllegalArgumentException if {@code fromIndex > toIndex}
* @throws ArrayIndexOutOfBoundsException
* if {@code fromIndex < 0} or {@code toIndex > a.length}
*/
public static void sort(byte[] a, int fromIndex, int toIndex) {
Arrays.checkStartAndEnd(a.length, fromIndex, toIndex);
doSort(a, fromIndex, toIndex - 1);
}
/** The number of distinct byte values. */
private static final int NUM_BYTE_VALUES = 1 << 8;
/**
* Sorts the specified range of the array into ascending order. This
* method differs from the public {@code sort} method in that the
* {@code right} index is inclusive, and it does no range checking on
* {@code left} or {@code right}.
*
* @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
*/
private static void doSort(byte[] a, int left, int right) {
// Use insertion sort on tiny arrays
if (right - left + 1 < INSERTION_SORT_THRESHOLD) {
for (int i = left + 1; i <= right; i++) {
byte ai = a[i];
int j;
for (j = i - 1; j >= left && ai < a[j]; j--) {
a[j + 1] = a[j];
}
a[j + 1] = ai;
}
} else if (right - left + 1 > COUNTING_SORT_THRESHOLD_FOR_BYTE) {
// Use counting sort on huge arrays
int[] count = new int[NUM_BYTE_VALUES];
for (int i = left; i <= right; i++) {
count[a[i] - Byte.MIN_VALUE]++;
}
for (int i = 0, k = left; i < count.length && k <= right; i++) {
byte value = (byte) (i + Byte.MIN_VALUE);
for (int s = count[i]; s > 0; s--) {
a[k++] = value;
}
}
} else { // Use Dual-Pivot Quicksort on large arrays
dualPivotQuicksort(a, left, right);
}
}
/**
* Sorts the specified range of the array into ascending order by the
* Dual-Pivot Quicksort algorithm.
*
* @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
*/
private static void dualPivotQuicksort(byte[] a, int left, int right) {
// Compute indices of five evenly spaced elements
int sixth = (right - left + 1) / 6;
int e1 = left + sixth;
int e5 = right - sixth;
int e3 = (left + right) >>> 1; // The midpoint
int e4 = e3 + sixth;
int e2 = e3 - sixth;
// Sort these elements using a 5-element sorting network
byte ae1 = a[e1], ae2 = a[e2], ae3 = a[e3], ae4 = a[e4], ae5 = a[e5];
if (ae1 > ae2) { byte t = ae1; ae1 = ae2; ae2 = t; }
if (ae4 > ae5) { byte t = ae4; ae4 = ae5; ae5 = t; }
if (ae1 > ae3) { byte t = ae1; ae1 = ae3; ae3 = t; }
if (ae2 > ae3) { byte t = ae2; ae2 = ae3; ae3 = t; }
if (ae1 > ae4) { byte t = ae1; ae1 = ae4; ae4 = t; }
if (ae3 > ae4) { byte t = ae3; ae3 = ae4; ae4 = t; }
if (ae2 > ae5) { byte t = ae2; ae2 = ae5; ae5 = t; }
if (ae2 > ae3) { byte t = ae2; ae2 = ae3; ae3 = t; }
if (ae4 > ae5) { byte t = ae4; ae4 = ae5; ae5 = t; }
a[e1] = ae1; a[e3] = ae3; a[e5] = ae5;
/*
* 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.
*
* The pivots are stored in local variables, and the first and
* the last of the 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 positions, and
* excluded from subsequent sorting.
*/
byte pivot1 = ae2; a[e2] = a[left];
byte pivot2 = ae4; a[e4] = a[right];
// Pointers
int less = left + 1; // The index of first element of center part
int great = right - 1; // The index before first element of right part
boolean pivotsDiffer = (pivot1 != pivot2);
if (pivotsDiffer) {
/*
* Partitioning:
*
* left part center part right part
* +------------------------------------------------------------+
* | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 |
* +------------------------------------------------------------+
* ^ ^ ^
* | | |
* less k great
*
* Invariants:
*
* all in (left, less) < pivot1
* pivot1 <= all in [less, k) <= pivot2
* all in (great, right) > pivot2
*
* Pointer k is the first index of ?-part
*/
outer:
for (int k = less; k <= great; k++) {
byte ak = a[k];
if (ak < pivot1) { // Move a[k] to left part
if (k != less) {
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[k] = a[less];
a[less++] = a[great];
a[great--] = ak;
} else { // pivot1 <= a[great] <= pivot2
a[k] = a[great];
a[great--] = ak;
}
}
}
} else { // Pivots are equal
/*
* Partition degenerates to the traditional 3-way,
* or "Dutch National Flag", partition:
*
* left part center part right part
* +----------------------------------------------+
* | < pivot | == pivot | ? | > pivot |
* +----------------------------------------------+
* ^ ^ ^
* | | |
* less k great
*
* Invariants:
*
* all in (left, less) < pivot
* all in [less, k) == pivot
* all in (great, right) > pivot
*
* Pointer k is the first index of ?-part
*/
for (int k = less; k <= great; k++) {
byte ak = a[k];
if (ak == pivot1) {
continue;
}
if (ak < pivot1) { // Move a[k] to left part
if (k != less) {
a[k] = a[less];
a[less] = ak;
}
less++;
} else { // (a[k] > pivot1) - Move a[k] to right part
/*
* We know that pivot1 == a[e3] == pivot2. Thus, we know
* that great will still be >= k when the following loop
* terminates, even though we don't test for it explicitly.
* In other words, a[e3] acts as a sentinel for great.
*/
while (a[great] > pivot1) {
great--;
}
if (a[great] < pivot1) {
a[k] = a[less];
a[less++] = a[great];
a[great--] = ak;
} else { // a[great] == pivot1
a[k] = pivot1;
a[great--] = ak;
}
}
}
}
// 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 pivot values
doSort(a, left, less - 2);
doSort(a, great + 2, right);
/*
* If pivot1 == pivot2, all elements from center
* part are equal and, therefore, already sorted
*/
if (!pivotsDiffer) {
return;
}
/*
* If center part is too large (comprises > 2/3 of the array),
* swap internal pivot values to ends
*/
if (less < e1 && great > e5) {
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; k <= great; k++) {
byte ak = a[k];
if (ak == pivot2) { // Move a[k] to right part
while (a[great] == pivot2) {
if (great-- == k) {
break outer;
}
}
if (a[great] == pivot1) {
a[k] = a[less];
a[less++] = pivot1;
} else { // pivot1 < a[great] < pivot2
a[k] = a[great];
}
a[great--] = pivot2;
} else if (ak == pivot1) { // Move a[k] to left part
a[k] = a[less];
a[less++] = pivot1;
}
}
}
// Sort center part recursively, excluding known pivot values
doSort(a, less, great);
}
/**
* Sorts the specified array into ascending numerical order.
*
* The {@code <} relation does not provide a total order on all float
* values: {@code -0.0f == 0.0f} is {@code true} and a {@code Float.NaN}
* value compares neither less than, greater than, nor equal to any value,
* even itself. This method uses the total order imposed by the method
* {@link Float#compareTo}: {@code -0.0f} is treated as less than value
* {@code 0.0f} and {@code Float.NaN} is considered greater than any
* other value and all {@code Float.NaN} values are considered equal.
*
* @param a the array to be sorted
*/
public static void sort(float[] a) {
sortNegZeroAndNaN(a, 0, a.length - 1);
}
/**
* Sorts the specified range of the array into ascending order. The range
* to be sorted extends from the index {@code fromIndex}, inclusive, to
* the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
* the range to be sorted is empty and the call is a no-op).
*
*
The {@code <} relation does not provide a total order on all float
* values: {@code -0.0f == 0.0f} is {@code true} and a {@code Float.NaN}
* value compares neither less than, greater than, nor equal to any value,
* even itself. This method uses the total order imposed by the method
* {@link Float#compareTo}: {@code -0.0f} is treated as less than value
* {@code 0.0f} and {@code Float.NaN} is considered greater than any
* other value and all {@code Float.NaN} values are considered equal.
*
* @param a the array to be sorted
* @param fromIndex the index of the first element, inclusive, to be sorted
* @param toIndex the index of the last element, exclusive, to be sorted
* @throws IllegalArgumentException if {@code fromIndex > toIndex}
* @throws ArrayIndexOutOfBoundsException
* if {@code fromIndex < 0} or {@code toIndex > a.length}
*/
public static void sort(float[] a, int fromIndex, int toIndex) {
Arrays.checkStartAndEnd(a.length, fromIndex, toIndex);
sortNegZeroAndNaN(a, fromIndex, toIndex - 1);
}
/**
* Sorts the specified range of the array into ascending order. The
* sort is done in three phases to avoid expensive comparisons in the
* inner loop. The comparisons would be expensive due to anomalies
* associated with negative zero {@code -0.0f} and {@code Float.NaN}.
*
* @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
*/
private static void sortNegZeroAndNaN(float[] a, int left, int right) {
/*
* Phase 1: Count negative zeros and move NaNs to end of array
*/
final int NEGATIVE_ZERO = Float.floatToIntBits(-0.0f);
int numNegativeZeros = 0;
int n = right;
for (int k = left; k <= n; k++) {
float ak = a[k];
if (ak == 0.0f && NEGATIVE_ZERO == Float.floatToRawIntBits(ak)) {
a[k] = 0.0f;
numNegativeZeros++;
} else if (ak != ak) { // i.e., ak is NaN
a[k--] = a[n];
a[n--] = Float.NaN;
}
}
/*
* Phase 2: Sort everything except NaNs (which are already in place)
*/
doSort(a, left, n);
/*
* Phase 3: Turn positive zeros back into negative zeros as appropriate
*/
if (numNegativeZeros == 0) {
return;
}
// Find first zero element
int zeroIndex = findAnyZero(a, left, n);
for (int i = zeroIndex - 1; i >= left && a[i] == 0.0f; i--) {
zeroIndex = i;
}
// Turn the right number of positive zeros back into negative zeros
for (int i = zeroIndex, m = zeroIndex + numNegativeZeros; i < m; i++) {
a[i] = -0.0f;
}
}
/**
* Returns the index of some zero element in the specified range via
* binary search. The range is assumed to be sorted, and must contain
* at least one zero.
*
* @param a the array to be searched
* @param low the index of the first element, inclusive, to be searched
* @param high the index of the last element, inclusive, to be searched
*/
private static int findAnyZero(float[] a, int low, int high) {
while (true) {
int middle = (low + high) >>> 1;
float middleValue = a[middle];
if (middleValue < 0.0f) {
low = middle + 1;
} else if (middleValue > 0.0f) {
high = middle - 1;
} else { // middleValue == 0.0f
return middle;
}
}
}
/**
* Sorts the specified range of the array into ascending order. This
* method differs from the public {@code sort} method in three ways:
* {@code right} index is inclusive, it does no range checking on
* {@code left} or {@code right}, and it does not handle negative
* zeros or NaNs in the array.
*
* @param a the array to be sorted, which must not contain -0.0f or NaN
* @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 doSort(float[] a, int left, int right) {
// Use insertion sort on tiny arrays
if (right - left + 1 < INSERTION_SORT_THRESHOLD) {
for (int i = left + 1; i <= right; i++) {
float ai = a[i];
int j;
for (j = i - 1; j >= left && ai < a[j]; j--) {
a[j + 1] = a[j];
}
a[j + 1] = ai;
}
} else { // Use Dual-Pivot Quicksort on large arrays
dualPivotQuicksort(a, left, right);
}
}
/**
* Sorts the specified range of the array into ascending order by the
* Dual-Pivot Quicksort algorithm.
*
* @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
*/
private static void dualPivotQuicksort(float[] a, int left, int right) {
// Compute indices of five evenly spaced elements
int sixth = (right - left + 1) / 6;
int e1 = left + sixth;
int e5 = right - sixth;
int e3 = (left + right) >>> 1; // The midpoint
int e4 = e3 + sixth;
int e2 = e3 - sixth;
// Sort these elements using a 5-element sorting network
float ae1 = a[e1], ae2 = a[e2], ae3 = a[e3], ae4 = a[e4], ae5 = a[e5];
if (ae1 > ae2) { float t = ae1; ae1 = ae2; ae2 = t; }
if (ae4 > ae5) { float t = ae4; ae4 = ae5; ae5 = t; }
if (ae1 > ae3) { float t = ae1; ae1 = ae3; ae3 = t; }
if (ae2 > ae3) { float t = ae2; ae2 = ae3; ae3 = t; }
if (ae1 > ae4) { float t = ae1; ae1 = ae4; ae4 = t; }
if (ae3 > ae4) { float t = ae3; ae3 = ae4; ae4 = t; }
if (ae2 > ae5) { float t = ae2; ae2 = ae5; ae5 = t; }
if (ae2 > ae3) { float t = ae2; ae2 = ae3; ae3 = t; }
if (ae4 > ae5) { float t = ae4; ae4 = ae5; ae5 = t; }
a[e1] = ae1; a[e3] = ae3; a[e5] = ae5;
/*
* 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.
*
* The pivots are stored in local variables, and the first and
* the last of the 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 positions, and
* excluded from subsequent sorting.
*/
float pivot1 = ae2; a[e2] = a[left];
float pivot2 = ae4; a[e4] = a[right];
// Pointers
int less = left + 1; // The index of first element of center part
int great = right - 1; // The index before first element of right part
boolean pivotsDiffer = (pivot1 != pivot2);
if (pivotsDiffer) {
/*
* Partitioning:
*
* left part center part right part
* +------------------------------------------------------------+
* | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 |
* +------------------------------------------------------------+
* ^ ^ ^
* | | |
* less k great
*
* Invariants:
*
* all in (left, less) < pivot1
* pivot1 <= all in [less, k) <= pivot2
* all in (great, right) > pivot2
*
* Pointer k is the first index of ?-part
*/
outer:
for (int k = less; k <= great; k++) {
float ak = a[k];
if (ak < pivot1) { // Move a[k] to left part
if (k != less) {
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[k] = a[less];
a[less++] = a[great];
a[great--] = ak;
} else { // pivot1 <= a[great] <= pivot2
a[k] = a[great];
a[great--] = ak;
}
}
}
} else { // Pivots are equal
/*
* Partition degenerates to the traditional 3-way,
* or "Dutch National Flag", partition:
*
* left part center part right part
* +----------------------------------------------+
* | < pivot | == pivot | ? | > pivot |
* +----------------------------------------------+
* ^ ^ ^
* | | |
* less k great
*
* Invariants:
*
* all in (left, less) < pivot
* all in [less, k) == pivot
* all in (great, right) > pivot
*
* Pointer k is the first index of ?-part
*/
for (int k = less; k <= great; k++) {
float ak = a[k];
if (ak == pivot1) {
continue;
}
if (ak < pivot1) { // Move a[k] to left part
if (k != less) {
a[k] = a[less];
a[less] = ak;
}
less++;
} else { // (a[k] > pivot1) - Move a[k] to right part
/*
* We know that pivot1 == a[e3] == pivot2. Thus, we know
* that great will still be >= k when the following loop
* terminates, even though we don't test for it explicitly.
* In other words, a[e3] acts as a sentinel for great.
*/
while (a[great] > pivot1) {
great--;
}
if (a[great] < pivot1) {
a[k] = a[less];
a[less++] = a[great];
a[great--] = ak;
} else { // a[great] == pivot1
a[k] = pivot1;
a[great--] = ak;
}
}
}
}
// 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 pivot values
doSort(a, left, less - 2);
doSort(a, great + 2, right);
/*
* If pivot1 == pivot2, all elements from center
* part are equal and, therefore, already sorted
*/
if (!pivotsDiffer) {
return;
}
/*
* If center part is too large (comprises > 2/3 of the array),
* swap internal pivot values to ends
*/
if (less < e1 && great > e5) {
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; k <= great; k++) {
float ak = a[k];
if (ak == pivot2) { // Move a[k] to right part
while (a[great] == pivot2) {
if (great-- == k) {
break outer;
}
}
if (a[great] == pivot1) {
a[k] = a[less];
a[less++] = pivot1;
} else { // pivot1 < a[great] < pivot2
a[k] = a[great];
}
a[great--] = pivot2;
} else if (ak == pivot1) { // Move a[k] to left part
a[k] = a[less];
a[less++] = pivot1;
}
}
}
// Sort center part recursively, excluding known pivot values
doSort(a, less, great);
}
/**
* Sorts the specified array into ascending numerical order.
*
*
The {@code <} relation does not provide a total order on all double
* values: {@code -0.0d == 0.0d} is {@code true} and a {@code Double.NaN}
* value compares neither less than, greater than, nor equal to any value,
* even itself. This method uses the total order imposed by the method
* {@link Double#compareTo}: {@code -0.0d} is treated as less than value
* {@code 0.0d} and {@code Double.NaN} is considered greater than any
* other value and all {@code Double.NaN} values are considered equal.
*
* @param a the array to be sorted
*/
public static void sort(double[] a) {
sortNegZeroAndNaN(a, 0, a.length - 1);
}
/**
* Sorts the specified range of the array into ascending order. The range
* to be sorted extends from the index {@code fromIndex}, inclusive, to
* the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
* the range to be sorted is empty (and the call is a no-op).
*
*
The {@code <} relation does not provide a total order on all double
* values: {@code -0.0d == 0.0d} is {@code true} and a {@code Double.NaN}
* value compares neither less than, greater than, nor equal to any value,
* even itself. This method uses the total order imposed by the method
* {@link Double#compareTo}: {@code -0.0d} is treated as less than value
* {@code 0.0d} and {@code Double.NaN} is considered greater than any
* other value and all {@code Double.NaN} values are considered equal.
*
* @param a the array to be sorted
* @param fromIndex the index of the first element, inclusive, to be sorted
* @param toIndex the index of the last element, exclusive, to be sorted
* @throws IllegalArgumentException if {@code fromIndex > toIndex}
* @throws ArrayIndexOutOfBoundsException
* if {@code fromIndex < 0} or {@code toIndex > a.length}
*/
public static void sort(double[] a, int fromIndex, int toIndex) {
Arrays.checkStartAndEnd(a.length, fromIndex, toIndex);
sortNegZeroAndNaN(a, fromIndex, toIndex - 1);
}
/**
* Sorts the specified range of the array into ascending order. The
* sort is done in three phases to avoid expensive comparisons in the
* inner loop. The comparisons would be expensive due to anomalies
* associated with negative zero {@code -0.0d} and {@code Double.NaN}.
*
* @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
*/
private static void sortNegZeroAndNaN(double[] a, int left, int right) {
/*
* Phase 1: Count negative zeros and move NaNs to end of array
*/
final long NEGATIVE_ZERO = Double.doubleToLongBits(-0.0d);
int numNegativeZeros = 0;
int n = right;
for (int k = left; k <= n; k++) {
double ak = a[k];
if (ak == 0.0d && NEGATIVE_ZERO == Double.doubleToRawLongBits(ak)) {
a[k] = 0.0d;
numNegativeZeros++;
} else if (ak != ak) { // i.e., ak is NaN
a[k--] = a[n];
a[n--] = Double.NaN;
}
}
/*
* Phase 2: Sort everything except NaNs (which are already in place)
*/
doSort(a, left, n);
/*
* Phase 3: Turn positive zeros back into negative zeros as appropriate
*/
if (numNegativeZeros == 0) {
return;
}
// Find first zero element
int zeroIndex = findAnyZero(a, left, n);
for (int i = zeroIndex - 1; i >= left && a[i] == 0.0d; i--) {
zeroIndex = i;
}
// Turn the right number of positive zeros back into negative zeros
for (int i = zeroIndex, m = zeroIndex + numNegativeZeros; i < m; i++) {
a[i] = -0.0d;
}
}
/**
* Returns the index of some zero element in the specified range via
* binary search. The range is assumed to be sorted, and must contain
* at least one zero.
*
* @param a the array to be searched
* @param low the index of the first element, inclusive, to be searched
* @param high the index of the last element, inclusive, to be searched
*/
private static int findAnyZero(double[] a, int low, int high) {
while (true) {
int middle = (low + high) >>> 1;
double middleValue = a[middle];
if (middleValue < 0.0d) {
low = middle + 1;
} else if (middleValue > 0.0d) {
high = middle - 1;
} else { // middleValue == 0.0d
return middle;
}
}
}
/**
* Sorts the specified range of the array into ascending order. This
* method differs from the public {@code sort} method in three ways:
* {@code right} index is inclusive, it does no range checking on
* {@code left} or {@code right}, and it does not handle negative
* zeros or NaNs in the array.
*
* @param a the array to be sorted, which must not contain -0.0d and NaN
* @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 doSort(double[] a, int left, int right) {
// Use insertion sort on tiny arrays
if (right - left + 1 < INSERTION_SORT_THRESHOLD) {
for (int i = left + 1; i <= right; i++) {
double ai = a[i];
int j;
for (j = i - 1; j >= left && ai < a[j]; j--) {
a[j + 1] = a[j];
}
a[j + 1] = ai;
}
} else { // Use Dual-Pivot Quicksort on large arrays
dualPivotQuicksort(a, left, right);
}
}
/**
* Sorts the specified range of the array into ascending order by the
* Dual-Pivot Quicksort algorithm.
*
* @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
*/
private static void dualPivotQuicksort(double[] a, int left, int right) {
// Compute indices of five evenly spaced elements
int sixth = (right - left + 1) / 6;
int e1 = left + sixth;
int e5 = right - sixth;
int e3 = (left + right) >>> 1; // The midpoint
int e4 = e3 + sixth;
int e2 = e3 - sixth;
// Sort these elements using a 5-element sorting network
double ae1 = a[e1], ae2 = a[e2], ae3 = a[e3], ae4 = a[e4], ae5 = a[e5];
if (ae1 > ae2) { double t = ae1; ae1 = ae2; ae2 = t; }
if (ae4 > ae5) { double t = ae4; ae4 = ae5; ae5 = t; }
if (ae1 > ae3) { double t = ae1; ae1 = ae3; ae3 = t; }
if (ae2 > ae3) { double t = ae2; ae2 = ae3; ae3 = t; }
if (ae1 > ae4) { double t = ae1; ae1 = ae4; ae4 = t; }
if (ae3 > ae4) { double t = ae3; ae3 = ae4; ae4 = t; }
if (ae2 > ae5) { double t = ae2; ae2 = ae5; ae5 = t; }
if (ae2 > ae3) { double t = ae2; ae2 = ae3; ae3 = t; }
if (ae4 > ae5) { double t = ae4; ae4 = ae5; ae5 = t; }
a[e1] = ae1; a[e3] = ae3; a[e5] = ae5;
/*
* 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.
*
* The pivots are stored in local variables, and the first and
* the last of the 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 positions, and
* excluded from subsequent sorting.
*/
double pivot1 = ae2; a[e2] = a[left];
double pivot2 = ae4; a[e4] = a[right];
// Pointers
int less = left + 1; // The index of first element of center part
int great = right - 1; // The index before first element of right part
boolean pivotsDiffer = (pivot1 != pivot2);
if (pivotsDiffer) {
/*
* Partitioning:
*
* left part center part right part
* +------------------------------------------------------------+
* | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 |
* +------------------------------------------------------------+
* ^ ^ ^
* | | |
* less k great
*
* Invariants:
*
* all in (left, less) < pivot1
* pivot1 <= all in [less, k) <= pivot2
* all in (great, right) > pivot2
*
* Pointer k is the first index of ?-part
*/
outer:
for (int k = less; k <= great; k++) {
double ak = a[k];
if (ak < pivot1) { // Move a[k] to left part
if (k != less) {
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[k] = a[less];
a[less++] = a[great];
a[great--] = ak;
} else { // pivot1 <= a[great] <= pivot2
a[k] = a[great];
a[great--] = ak;
}
}
}
} else { // Pivots are equal
/*
* Partition degenerates to the traditional 3-way,
* or "Dutch National Flag", partition:
*
* left part center part right part
* +----------------------------------------------+
* | < pivot | == pivot | ? | > pivot |
* +----------------------------------------------+
* ^ ^ ^
* | | |
* less k great
*
* Invariants:
*
* all in (left, less) < pivot
* all in [less, k) == pivot
* all in (great, right) > pivot
*
* Pointer k is the first index of ?-part
*/
for (int k = less; k <= great; k++) {
double ak = a[k];
if (ak == pivot1) {
continue;
}
if (ak < pivot1) { // Move a[k] to left part
if (k != less) {
a[k] = a[less];
a[less] = ak;
}
less++;
} else { // (a[k] > pivot1) - Move a[k] to right part
/*
* We know that pivot1 == a[e3] == pivot2. Thus, we know
* that great will still be >= k when the following loop
* terminates, even though we don't test for it explicitly.
* In other words, a[e3] acts as a sentinel for great.
*/
while (a[great] > pivot1) {
great--;
}
if (a[great] < pivot1) {
a[k] = a[less];
a[less++] = a[great];
a[great--] = ak;
} else { // a[great] == pivot1
a[k] = pivot1;
a[great--] = ak;
}
}
}
}
// 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 pivot values
doSort(a, left, less - 2);
doSort(a, great + 2, right);
/*
* If pivot1 == pivot2, all elements from center
* part are equal and, therefore, already sorted
*/
if (!pivotsDiffer) {
return;
}
/*
* If center part is too large (comprises > 2/3 of the array),
* swap internal pivot values to ends
*/
if (less < e1 && great > e5) {
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; k <= great; k++) {
double ak = a[k];
if (ak == pivot2) { // Move a[k] to right part
while (a[great] == pivot2) {
if (great-- == k) {
break outer;
}
}
if (a[great] == pivot1) {
a[k] = a[less];
a[less++] = pivot1;
} else { // pivot1 < a[great] < pivot2
a[k] = a[great];
}
a[great--] = pivot2;
} else if (ak == pivot1) { // Move a[k] to left part
a[k] = a[less];
a[less++] = pivot1;
}
}
}
// Sort center part recursively, excluding known pivot values
doSort(a, less, great);
}
}