All Downloads are FREE. Search and download functionalities are using the official Maven repository.

java.util.DualPivotQuicksort Maven / Gradle / Ivy

/*
 *  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); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy