--- old/src/share/classes/java/util/DualPivotQuicksort.java Mon Apr 26 16:04:03 2010 +++ new/src/share/classes/java/util/DualPivotQuicksort.java Mon Apr 26 16:04:02 2010 @@ -1,5 +1,5 @@ /* - * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2010 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,7 @@ /** * This class implements the Dual-Pivot Quicksort algorithm by - * Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. The algorithm + * Vladimir Yaroslavskiy, Jon Bentley, and Josh 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. @@ -36,7 +36,8 @@ * @author Jon Bentley * @author Josh Bloch * - * @version 2009.11.29 m765.827.12i + * @version 2010.04.25 m765.827.12i:5\7 + * @since 1.7 */ final class DualPivotQuicksort { @@ -68,7 +69,7 @@ private static final int COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR = 32768; /* - * Sorting methods for 7 primitive types. + * Sorting methods for seven primitive types. */ /** @@ -77,7 +78,7 @@ * @param a the array to be sorted */ public static void sort(int[] a) { - doSort(a, 0, a.length - 1); + dualPivotQuicksort(a, 0, a.length - 1); } /** @@ -95,54 +96,72 @@ */ public static void sort(int[] a, int fromIndex, int toIndex) { rangeCheck(a.length, fromIndex, toIndex); - doSort(a, fromIndex, toIndex - 1); + dualPivotQuicksort(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}. + * 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 doSort(int[] a, int left, int right) { + private static void dualPivotQuicksort(int[] a, int left, int right) { + int length = right - left + 1; + + // Skip trivial arrays + if (length < 2) { + return; + } + // 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]; + if (length < INSERTION_SORT_THRESHOLD) { + if (left > 0) { + /* + * Set minimum value as a sentinel before the specified + * range of the array, it allows to avoid expensive + * check j >= left on each iteration. + */ + int before = a[left - 1]; a[left - 1] = Integer.MIN_VALUE; + + for (int j, i = left + 1; i <= right; i++) { + int ai = a[i]; + for (j = i - 1; /* j >= left && */ ai < a[j]; j--) { + a[j + 1] = a[j]; + } + a[j + 1] = ai; } - a[j + 1] = ai; + a[left - 1] = before; + } else { + /* + * For case, when left == 0, traditional (without a sentinel) + * insertion sort, optimized for server VM, is used. + */ + for (int i = 0, j = i; i < right; j = ++i) { + int ai = a[i + 1]; + while (ai < a[j]) { + a[j + 1] = a[j]; + if (j-- == 0) { + break; + } + } + a[j + 1] = ai; + } } - } else { // Use Dual-Pivot Quicksort on large arrays - dualPivotQuicksort(a, left, right); + return; } - } - /** - * 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; + // Inexpensive approximation of one seventh + int seventh = (length >>> 3) + (length >>> 6) + 1; + + // Compute indices of 5 center evenly spaced elements int e3 = (left + right) >>> 1; // The midpoint - int e4 = e3 + sixth; - int e2 = e3 - sixth; + int e2 = e3 - seventh, e1 = e2 - seventh; + int e4 = e3 + seventh, e5 = e4 + seventh; // 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]; + int ae1 = a[e1], ae3 = a[e3], ae5 = a[e5], ae2 = a[e2], ae4 = a[e4]; if (ae1 > ae2) { int t = ae1; ae1 = ae2; ae2 = t; } if (ae4 > ae5) { int t = ae4; ae4 = ae5; ae5 = t; } @@ -154,39 +173,40 @@ 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; + a[e1] = ae1; a[e3] = ae3; a[e5] = ae5; a[e2] = ae2; a[e4] = ae4; /* * 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]; + int pivot1 = a[e2]; + int pivot2 = a[e4]; // 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 + int less = left; // The index of the first element of center part + int great = right; // The index before the first element of right part - boolean pivotsDiffer = (pivot1 != pivot2); + if (pivot1 < pivot2) { + /* + * The first and the last 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. + */ + a[e2] = a[less++]; + a[e4] = a[great--]; - if (pivotsDiffer) { /* * Partitioning: * - * left part center part right part - * +------------------------------------------------------------+ - * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 | - * +------------------------------------------------------------+ - * ^ ^ ^ - * | | | - * less k great + * left part center part right part + * +--------------------------------------------------------------+ + * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 | + * +--------------------------------------------------------------+ + * ^ ^ ^ + * | | | + * less k great * * Invariants: * @@ -194,7 +214,7 @@ * pivot1 <= all in [less, k) <= pivot2 * all in (great, right) > pivot2 * - * Pointer k is the first index of ?-part + * Pointer k is the first index of not inspected ?-part. */ outer: for (int k = less; k <= great; k++) { @@ -214,17 +234,82 @@ 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; } + 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 pivots + dualPivotQuicksort(a, left, less - 2); + dualPivotQuicksort(a, great + 2, right); + + /* + * If center part is too large (comprises > 5/7 of the array), + * swap internal pivot values to ends. + */ + if (great - less > 5 * seventh) { + 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 not inspected ?-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 + dualPivotQuicksort(a, less, great); + } else { // Pivots are equal /* - * Partition degenerates to the traditional 3-way, - * or "Dutch National Flag", partition: + * Partition degenerates to the traditional 3-way + * (or "Dutch National Flag") schema: * * left part center part right part * +----------------------------------------------+ @@ -240,7 +325,7 @@ * all in [less, k) == pivot * all in (great, right) > pivot * - * Pointer k is the first index of ?-part + * Pointer k is the first index of not inspected ?-part. */ for (int k = less; k <= great; k++) { int ak = a[k]; @@ -253,7 +338,7 @@ a[less] = ak; } less++; - } else { // (a[k] > pivot1) - Move a[k] to right part + } 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 @@ -266,87 +351,17 @@ 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; } + 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; + // Sort left and right parts recursively + dualPivotQuicksort(a, left, less - 1); + dualPivotQuicksort(a, great + 1, right); } - - /* - * 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); } /** @@ -355,7 +370,7 @@ * @param a the array to be sorted */ public static void sort(long[] a) { - doSort(a, 0, a.length - 1); + dualPivotQuicksort(a, 0, a.length - 1); } /** @@ -373,54 +388,72 @@ */ public static void sort(long[] a, int fromIndex, int toIndex) { rangeCheck(a.length, fromIndex, toIndex); - doSort(a, fromIndex, toIndex - 1); + dualPivotQuicksort(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}. + * 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 doSort(long[] a, int left, int right) { + private static void dualPivotQuicksort(long[] a, int left, int right) { + int length = right - left + 1; + + // Skip trivial arrays + if (length < 2) { + return; + } + // 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]; + if (length < INSERTION_SORT_THRESHOLD) { + if (left > 0) { + /* + * Set minimum value as a sentinel before the specified + * range of the array, it allows to avoid expensive + * check j >= left on each iteration. + */ + long before = a[left - 1]; a[left - 1] = Long.MIN_VALUE; + + for (int j, i = left + 1; i <= right; i++) { + long ai = a[i]; + for (j = i - 1; /* j >= left && */ ai < a[j]; j--) { + a[j + 1] = a[j]; + } + a[j + 1] = ai; } - a[j + 1] = ai; + a[left - 1] = before; + } else { + /* + * For case, when left == 0, traditional (without a sentinel) + * insertion sort, optimized for server VM, is used. + */ + for (int i = 0, j = i; i < right; j = ++i) { + long ai = a[i + 1]; + while (ai < a[j]) { + a[j + 1] = a[j]; + if (j-- == 0) { + break; + } + } + a[j + 1] = ai; + } } - } else { // Use Dual-Pivot Quicksort on large arrays - dualPivotQuicksort(a, left, right); + return; } - } - /** - * 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; + // Inexpensive approximation of one seventh + int seventh = (length >>> 3) + (length >>> 6) + 1; + + // Compute indices of 5 center evenly spaced elements int e3 = (left + right) >>> 1; // The midpoint - int e4 = e3 + sixth; - int e2 = e3 - sixth; + int e2 = e3 - seventh, e1 = e2 - seventh; + int e4 = e3 + seventh, e5 = e4 + seventh; // 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]; + long ae1 = a[e1], ae3 = a[e3], ae5 = a[e5], ae2 = a[e2], ae4 = a[e4]; if (ae1 > ae2) { long t = ae1; ae1 = ae2; ae2 = t; } if (ae4 > ae5) { long t = ae4; ae4 = ae5; ae5 = t; } @@ -432,39 +465,40 @@ 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; + a[e1] = ae1; a[e3] = ae3; a[e5] = ae5; a[e2] = ae2; a[e4] = ae4; /* * 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]; + long pivot1 = a[e2]; + long pivot2 = a[e4]; // 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 + int less = left; // The index of the first element of center part + int great = right; // The index before the first element of right part - boolean pivotsDiffer = (pivot1 != pivot2); + if (pivot1 < pivot2) { + /* + * The first and the last 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. + */ + a[e2] = a[less++]; + a[e4] = a[great--]; - if (pivotsDiffer) { /* * Partitioning: * - * left part center part right part - * +------------------------------------------------------------+ - * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 | - * +------------------------------------------------------------+ - * ^ ^ ^ - * | | | - * less k great + * left part center part right part + * +--------------------------------------------------------------+ + * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 | + * +--------------------------------------------------------------+ + * ^ ^ ^ + * | | | + * less k great * * Invariants: * @@ -472,7 +506,7 @@ * pivot1 <= all in [less, k) <= pivot2 * all in (great, right) > pivot2 * - * Pointer k is the first index of ?-part + * Pointer k is the first index of not inspected ?-part. */ outer: for (int k = less; k <= great; k++) { @@ -492,17 +526,82 @@ 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; } + 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 pivots + dualPivotQuicksort(a, left, less - 2); + dualPivotQuicksort(a, great + 2, right); + + /* + * If center part is too large (comprises > 5/7 of the array), + * swap internal pivot values to ends. + */ + if (great - less > 5 * seventh) { + 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 not inspected ?-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 + dualPivotQuicksort(a, less, great); + } else { // Pivots are equal /* - * Partition degenerates to the traditional 3-way, - * or "Dutch National Flag", partition: + * Partition degenerates to the traditional 3-way + * (or "Dutch National Flag") schema: * * left part center part right part * +----------------------------------------------+ @@ -518,7 +617,7 @@ * all in [less, k) == pivot * all in (great, right) > pivot * - * Pointer k is the first index of ?-part + * Pointer k is the first index of not inspected ?-part. */ for (int k = less; k <= great; k++) { long ak = a[k]; @@ -531,7 +630,7 @@ a[less] = ak; } less++; - } else { // (a[k] > pivot1) - Move a[k] to right part + } 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 @@ -544,87 +643,17 @@ 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; } + 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; + // Sort left and right parts recursively + dualPivotQuicksort(a, left, less - 1); + dualPivotQuicksort(a, great + 1, right); } - - /* - * 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); } /** @@ -633,7 +662,7 @@ * @param a the array to be sorted */ public static void sort(short[] a) { - doSort(a, 0, a.length - 1); + dualPivotQuicksort(a, 0, a.length - 1); } /** @@ -651,7 +680,7 @@ */ public static void sort(short[] a, int fromIndex, int toIndex) { rangeCheck(a.length, fromIndex, toIndex); - doSort(a, fromIndex, toIndex - 1); + dualPivotQuicksort(a, fromIndex, toIndex - 1); } /** The number of distinct short values. */ @@ -658,28 +687,60 @@ 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}. + * 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 doSort(short[] a, int left, int right) { + private static void dualPivotQuicksort(short[] a, int left, int right) { + int length = right - left + 1; + + // Skip trivial arrays + if (length < 2) { + return; + } + // 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]; + if (length < INSERTION_SORT_THRESHOLD) { + if (left > 0) { + /* + * Set minimum value as a sentinel before the specified + * range of the array, it allows to avoid expensive + * check j >= left on each iteration. + */ + short before = a[left - 1]; a[left - 1] = Short.MIN_VALUE; + + for (int j, i = left + 1; i <= right; i++) { + short ai = a[i]; + for (j = i - 1; /* j >= left && */ ai < a[j]; j--) { + a[j + 1] = a[j]; + } + a[j + 1] = ai; } - a[j + 1] = ai; + a[left - 1] = before; + } else { + /* + * For case, when left == 0, traditional (without a sentinel) + * insertion sort, optimized for server VM, is used. + */ + for (int i = 0, j = i; i < right; j = ++i) { + short ai = a[i + 1]; + while (ai < a[j]) { + a[j + 1] = a[j]; + if (j-- == 0) { + break; + } + } + a[j + 1] = ai; + } } - } else if (right-left+1 > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) { - // Use counting sort on huge arrays + return; + } + + // Use counting sort on huge arrays + if (length > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) { int[] count = new int[NUM_SHORT_VALUES]; for (int i = left; i <= right; i++) { @@ -692,30 +753,19 @@ a[k++] = value; } } - } else { // Use Dual-Pivot Quicksort on large arrays - dualPivotQuicksort(a, left, right); + return; } - } - /** - * 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; + // Inexpensive approximation of one seventh + int seventh = (length >>> 3) + (length >>> 6) + 1; + + // Compute indices of 5 center evenly spaced elements int e3 = (left + right) >>> 1; // The midpoint - int e4 = e3 + sixth; - int e2 = e3 - sixth; + int e2 = e3 - seventh, e1 = e2 - seventh; + int e4 = e3 + seventh, e5 = e4 + seventh; // 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]; + short ae1 = a[e1], ae3 = a[e3], ae5 = a[e5], ae2 = a[e2], ae4 = a[e4]; if (ae1 > ae2) { short t = ae1; ae1 = ae2; ae2 = t; } if (ae4 > ae5) { short t = ae4; ae4 = ae5; ae5 = t; } @@ -727,39 +777,40 @@ 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; + a[e1] = ae1; a[e3] = ae3; a[e5] = ae5; a[e2] = ae2; a[e4] = ae4; /* * 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]; + short pivot1 = a[e2]; + short pivot2 = a[e4]; // 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 + int less = left; // The index of the first element of center part + int great = right; // The index before the first element of right part - boolean pivotsDiffer = (pivot1 != pivot2); + if (pivot1 < pivot2) { + /* + * The first and the last 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. + */ + a[e2] = a[less++]; + a[e4] = a[great--]; - if (pivotsDiffer) { /* * Partitioning: * - * left part center part right part - * +------------------------------------------------------------+ - * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 | - * +------------------------------------------------------------+ - * ^ ^ ^ - * | | | - * less k great + * left part center part right part + * +--------------------------------------------------------------+ + * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 | + * +--------------------------------------------------------------+ + * ^ ^ ^ + * | | | + * less k great * * Invariants: * @@ -767,7 +818,7 @@ * pivot1 <= all in [less, k) <= pivot2 * all in (great, right) > pivot2 * - * Pointer k is the first index of ?-part + * Pointer k is the first index of not inspected ?-part. */ outer: for (int k = less; k <= great; k++) { @@ -787,17 +838,82 @@ 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; } + 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 pivots + dualPivotQuicksort(a, left, less - 2); + dualPivotQuicksort(a, great + 2, right); + + /* + * If center part is too large (comprises > 5/7 of the array), + * swap internal pivot values to ends. + */ + if (great - less > 5 * seventh) { + 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 not inspected ?-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 + dualPivotQuicksort(a, less, great); + } else { // Pivots are equal /* - * Partition degenerates to the traditional 3-way, - * or "Dutch National Flag", partition: + * Partition degenerates to the traditional 3-way + * (or "Dutch National Flag") schema: * * left part center part right part * +----------------------------------------------+ @@ -813,7 +929,7 @@ * all in [less, k) == pivot * all in (great, right) > pivot * - * Pointer k is the first index of ?-part + * Pointer k is the first index of not inspected ?-part. */ for (int k = less; k <= great; k++) { short ak = a[k]; @@ -826,7 +942,7 @@ a[less] = ak; } less++; - } else { // (a[k] > pivot1) - Move a[k] to right part + } 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 @@ -839,87 +955,17 @@ 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; } + 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; + // Sort left and right parts recursively + dualPivotQuicksort(a, left, less - 1); + dualPivotQuicksort(a, great + 1, right); } - - /* - * 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); } /** @@ -928,7 +974,7 @@ * @param a the array to be sorted */ public static void sort(char[] a) { - doSort(a, 0, a.length - 1); + dualPivotQuicksort(a, 0, a.length - 1); } /** @@ -946,7 +992,7 @@ */ public static void sort(char[] a, int fromIndex, int toIndex) { rangeCheck(a.length, fromIndex, toIndex); - doSort(a, fromIndex, toIndex - 1); + dualPivotQuicksort(a, fromIndex, toIndex - 1); } /** The number of distinct char values. */ @@ -953,28 +999,60 @@ 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}. + * 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 doSort(char[] a, int left, int right) { + private static void dualPivotQuicksort(char[] a, int left, int right) { + int length = right - left + 1; + + // Skip trivial arrays + if (length < 2) { + return; + } + // 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]; + if (length < INSERTION_SORT_THRESHOLD) { + if (left > 0) { + /* + * Set minimum value as a sentinel before the specified + * range of the array, it allows to avoid expensive + * check j >= left on each iteration. + */ + char before = a[left - 1]; a[left - 1] = Character.MIN_VALUE; + + for (int j, i = left + 1; i <= right; i++) { + char ai = a[i]; + for (j = i - 1; /* j >= left && */ ai < a[j]; j--) { + a[j + 1] = a[j]; + } + a[j + 1] = ai; } - a[j + 1] = ai; + a[left - 1] = before; + } else { + /* + * For case, when left == 0, traditional (without a sentinel) + * insertion sort, optimized for server VM, is used. + */ + for (int i = 0, j = i; i < right; j = ++i) { + char ai = a[i + 1]; + while (ai < a[j]) { + a[j + 1] = a[j]; + if (j-- == 0) { + break; + } + } + a[j + 1] = ai; + } } - } else if (right-left+1 > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) { - // Use counting sort on huge arrays + return; + } + + // Use counting sort on huge arrays + if (length > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) { int[] count = new int[NUM_CHAR_VALUES]; for (int i = left; i <= right; i++) { @@ -985,30 +1063,19 @@ a[k++] = (char) i; } } - } else { // Use Dual-Pivot Quicksort on large arrays - dualPivotQuicksort(a, left, right); + return; } - } - /** - * 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; + // Inexpensive approximation of one seventh + int seventh = (length >>> 3) + (length >>> 6) + 1; + + // Compute indices of 5 center evenly spaced elements int e3 = (left + right) >>> 1; // The midpoint - int e4 = e3 + sixth; - int e2 = e3 - sixth; + int e2 = e3 - seventh, e1 = e2 - seventh; + int e4 = e3 + seventh, e5 = e4 + seventh; // 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]; + char ae1 = a[e1], ae3 = a[e3], ae5 = a[e5], ae2 = a[e2], ae4 = a[e4]; if (ae1 > ae2) { char t = ae1; ae1 = ae2; ae2 = t; } if (ae4 > ae5) { char t = ae4; ae4 = ae5; ae5 = t; } @@ -1020,39 +1087,40 @@ 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; + a[e1] = ae1; a[e3] = ae3; a[e5] = ae5; a[e2] = ae2; a[e4] = ae4; /* * 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]; + char pivot1 = a[e2]; + char pivot2 = a[e4]; // 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 + int less = left; // The index of the first element of center part + int great = right; // The index before the first element of right part - boolean pivotsDiffer = (pivot1 != pivot2); + if (pivot1 < pivot2) { + /* + * The first and the last 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. + */ + a[e2] = a[less++]; + a[e4] = a[great--]; - if (pivotsDiffer) { /* * Partitioning: * - * left part center part right part - * +------------------------------------------------------------+ - * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 | - * +------------------------------------------------------------+ - * ^ ^ ^ - * | | | - * less k great + * left part center part right part + * +--------------------------------------------------------------+ + * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 | + * +--------------------------------------------------------------+ + * ^ ^ ^ + * | | | + * less k great * * Invariants: * @@ -1060,7 +1128,7 @@ * pivot1 <= all in [less, k) <= pivot2 * all in (great, right) > pivot2 * - * Pointer k is the first index of ?-part + * Pointer k is the first index of not inspected ?-part. */ outer: for (int k = less; k <= great; k++) { @@ -1080,17 +1148,82 @@ 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; } + 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 pivots + dualPivotQuicksort(a, left, less - 2); + dualPivotQuicksort(a, great + 2, right); + + /* + * If center part is too large (comprises > 5/7 of the array), + * swap internal pivot values to ends. + */ + if (great - less > 5 * seventh) { + 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 not inspected ?-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 + dualPivotQuicksort(a, less, great); + } else { // Pivots are equal /* - * Partition degenerates to the traditional 3-way, - * or "Dutch National Flag", partition: + * Partition degenerates to the traditional 3-way + * (or "Dutch National Flag") schema: * * left part center part right part * +----------------------------------------------+ @@ -1106,7 +1239,7 @@ * all in [less, k) == pivot * all in (great, right) > pivot * - * Pointer k is the first index of ?-part + * Pointer k is the first index of not inspected ?-part. */ for (int k = less; k <= great; k++) { char ak = a[k]; @@ -1119,7 +1252,7 @@ a[less] = ak; } less++; - } else { // (a[k] > pivot1) - Move a[k] to right part + } 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 @@ -1132,87 +1265,17 @@ 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; } + 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; + // Sort left and right parts recursively + dualPivotQuicksort(a, left, less - 1); + dualPivotQuicksort(a, great + 1, right); } - - /* - * 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); } /** @@ -1221,7 +1284,7 @@ * @param a the array to be sorted */ public static void sort(byte[] a) { - doSort(a, 0, a.length - 1); + dualPivotQuicksort(a, 0, a.length - 1); } /** @@ -1239,7 +1302,7 @@ */ public static void sort(byte[] a, int fromIndex, int toIndex) { rangeCheck(a.length, fromIndex, toIndex); - doSort(a, fromIndex, toIndex - 1); + dualPivotQuicksort(a, fromIndex, toIndex - 1); } /** The number of distinct byte values. */ @@ -1246,28 +1309,60 @@ 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}. + * 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 doSort(byte[] a, int left, int right) { + private static void dualPivotQuicksort(byte[] a, int left, int right) { + int length = right - left + 1; + + // Skip trivial arrays + if (length < 2) { + return; + } + // 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]; + if (length < INSERTION_SORT_THRESHOLD) { + if (left > 0) { + /* + * Set minimum value as a sentinel before the specified + * range of the array, it allows to avoid expensive + * check j >= left on each iteration. + */ + byte before = a[left - 1]; a[left - 1] = Byte.MIN_VALUE; + + for (int j, i = left + 1; i <= right; i++) { + byte ai = a[i]; + for (j = i - 1; /* j >= left && */ ai < a[j]; j--) { + a[j + 1] = a[j]; + } + a[j + 1] = ai; } - a[j + 1] = ai; + a[left - 1] = before; + } else { + /* + * For case, when left == 0, traditional (without a sentinel) + * insertion sort, optimized for server VM, is used. + */ + for (int i = 0, j = i; i < right; j = ++i) { + byte ai = a[i + 1]; + while (ai < a[j]) { + a[j + 1] = a[j]; + if (j-- == 0) { + break; + } + } + a[j + 1] = ai; + } } - } else if (right - left + 1 > COUNTING_SORT_THRESHOLD_FOR_BYTE) { - // Use counting sort on huge arrays + return; + } + + // Use counting sort on huge arrays + if (length > COUNTING_SORT_THRESHOLD_FOR_BYTE) { int[] count = new int[NUM_BYTE_VALUES]; for (int i = left; i <= right; i++) { @@ -1280,30 +1375,19 @@ a[k++] = value; } } - } else { // Use Dual-Pivot Quicksort on large arrays - dualPivotQuicksort(a, left, right); + return; } - } - /** - * 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; + // Inexpensive approximation of one seventh + int seventh = (length >>> 3) + (length >>> 6) + 1; + + // Compute indices of 5 center evenly spaced elements int e3 = (left + right) >>> 1; // The midpoint - int e4 = e3 + sixth; - int e2 = e3 - sixth; + int e2 = e3 - seventh, e1 = e2 - seventh; + int e4 = e3 + seventh, e5 = e4 + seventh; // 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]; + byte ae1 = a[e1], ae3 = a[e3], ae5 = a[e5], ae2 = a[e2], ae4 = a[e4]; if (ae1 > ae2) { byte t = ae1; ae1 = ae2; ae2 = t; } if (ae4 > ae5) { byte t = ae4; ae4 = ae5; ae5 = t; } @@ -1315,39 +1399,40 @@ 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; + a[e1] = ae1; a[e3] = ae3; a[e5] = ae5; a[e2] = ae2; a[e4] = ae4; /* * 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]; + byte pivot1 = a[e2]; + byte pivot2 = a[e4]; // 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 + int less = left; // The index of the first element of center part + int great = right; // The index before the first element of right part - boolean pivotsDiffer = (pivot1 != pivot2); + if (pivot1 < pivot2) { + /* + * The first and the last 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. + */ + a[e2] = a[less++]; + a[e4] = a[great--]; - if (pivotsDiffer) { /* * Partitioning: * - * left part center part right part - * +------------------------------------------------------------+ - * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 | - * +------------------------------------------------------------+ - * ^ ^ ^ - * | | | - * less k great + * left part center part right part + * +--------------------------------------------------------------+ + * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 | + * +--------------------------------------------------------------+ + * ^ ^ ^ + * | | | + * less k great * * Invariants: * @@ -1355,7 +1440,7 @@ * pivot1 <= all in [less, k) <= pivot2 * all in (great, right) > pivot2 * - * Pointer k is the first index of ?-part + * Pointer k is the first index of not inspected ?-part. */ outer: for (int k = less; k <= great; k++) { @@ -1375,17 +1460,82 @@ 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; } + 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 pivots + dualPivotQuicksort(a, left, less - 2); + dualPivotQuicksort(a, great + 2, right); + + /* + * If center part is too large (comprises > 5/7 of the array), + * swap internal pivot values to ends. + */ + if (great - less > 5 * seventh) { + 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 not inspected ?-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 + dualPivotQuicksort(a, less, great); + } else { // Pivots are equal /* - * Partition degenerates to the traditional 3-way, - * or "Dutch National Flag", partition: + * Partition degenerates to the traditional 3-way + * (or "Dutch National Flag") schema: * * left part center part right part * +----------------------------------------------+ @@ -1401,7 +1551,7 @@ * all in [less, k) == pivot * all in (great, right) > pivot * - * Pointer k is the first index of ?-part + * Pointer k is the first index of not inspected ?-part. */ for (int k = less; k <= great; k++) { byte ak = a[k]; @@ -1414,7 +1564,7 @@ a[less] = ak; } less++; - } else { // (a[k] > pivot1) - Move a[k] to right part + } 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 @@ -1427,87 +1577,17 @@ 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; } + 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; + // Sort left and right parts recursively + dualPivotQuicksort(a, left, less - 1); + dualPivotQuicksort(a, great + 1, right); } - - /* - * 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); } /** @@ -1531,7 +1611,7 @@ * 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 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} @@ -1565,7 +1645,7 @@ */ private static void sortNegZeroAndNaN(float[] a, int left, int right) { /* - * Phase 1: Count negative zeros and move NaNs to end of array + * Phase 1: Count negative zeros and move NaNs to end of array. */ final int NEGATIVE_ZERO = Float.floatToIntBits(-0.0f); int numNegativeZeros = 0; @@ -1583,12 +1663,12 @@ } /* - * Phase 2: Sort everything except NaNs (which are already in place) + * Phase 2: Sort everything except NaNs (which are already in place). */ - doSort(a, left, n); + dualPivotQuicksort(a, left, n); /* - * Phase 3: Turn positive zeros back into negative zeros as appropriate + * Phase 3: Turn positive zeros back into negative zeros. */ if (numNegativeZeros == 0) { return; @@ -1632,51 +1712,68 @@ } /** - * 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. + * Sorts the specified range of the array into ascending order by the + * Dual-Pivot Quicksort algorithm. * - * @param a the array to be sorted, which must not contain -0.0f or 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 doSort(float[] a, int left, int right) { + private static void dualPivotQuicksort(float[] a, int left, int right) { + int length = right - left + 1; + + // Skip trivial arrays + if (length < 2) { + return; + } + // 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]; + if (length < INSERTION_SORT_THRESHOLD) { + if (left > 0) { + /* + * Set negative infinity as a sentinel before the specified + * range of the array, it allows to avoid expensive + * check j >= left on each iteration. + */ + float before = a[left-1]; a[left-1] = Float.NEGATIVE_INFINITY; + + for (int j, i = left + 1; i <= right; i++) { + float ai = a[i]; + for (j = i - 1; /* j >= left && */ ai < a[j]; j--) { + a[j + 1] = a[j]; + } + a[j + 1] = ai; } - a[j + 1] = ai; + a[left - 1] = before; + } else { + /* + * For case, when left == 0, traditional (without a sentinel) + * insertion sort, optimized for server VM, is used. + */ + for (int i = 0, j = i; i < right; j = ++i) { + float ai = a[i + 1]; + while (ai < a[j]) { + a[j + 1] = a[j]; + if (j-- == 0) { + break; + } + } + a[j + 1] = ai; + } } - } else { // Use Dual-Pivot Quicksort on large arrays - dualPivotQuicksort(a, left, right); + return; } - } - /** - * 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; + // Inexpensive approximation of one seventh + int seventh = (length >>> 3) + (length >>> 6) + 1; + + // Compute indices of 5 center evenly spaced elements int e3 = (left + right) >>> 1; // The midpoint - int e4 = e3 + sixth; - int e2 = e3 - sixth; + int e2 = e3 - seventh, e1 = e2 - seventh; + int e4 = e3 + seventh, e5 = e4 + seventh; // 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]; + float ae1 = a[e1], ae3 = a[e3], ae5 = a[e5], ae2 = a[e2], ae4 = a[e4]; if (ae1 > ae2) { float t = ae1; ae1 = ae2; ae2 = t; } if (ae4 > ae5) { float t = ae4; ae4 = ae5; ae5 = t; } @@ -1688,39 +1785,40 @@ 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; + a[e1] = ae1; a[e3] = ae3; a[e5] = ae5; a[e2] = ae2; a[e4] = ae4; /* * 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]; + float pivot1 = a[e2]; + float pivot2 = a[e4]; // 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 + int less = left; // The index of the first element of center part + int great = right; // The index before the first element of right part - boolean pivotsDiffer = (pivot1 != pivot2); + if (pivot1 < pivot2) { + /* + * The first and the last 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. + */ + a[e2] = a[less++]; + a[e4] = a[great--]; - if (pivotsDiffer) { /* * Partitioning: * - * left part center part right part - * +------------------------------------------------------------+ - * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 | - * +------------------------------------------------------------+ - * ^ ^ ^ - * | | | - * less k great + * left part center part right part + * +--------------------------------------------------------------+ + * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 | + * +--------------------------------------------------------------+ + * ^ ^ ^ + * | | | + * less k great * * Invariants: * @@ -1728,7 +1826,7 @@ * pivot1 <= all in [less, k) <= pivot2 * all in (great, right) > pivot2 * - * Pointer k is the first index of ?-part + * Pointer k is the first index of not inspected ?-part. */ outer: for (int k = less; k <= great; k++) { @@ -1748,17 +1846,82 @@ 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; } + 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 pivots + dualPivotQuicksort(a, left, less - 2); + dualPivotQuicksort(a, great + 2, right); + + /* + * If center part is too large (comprises > 5/7 of the array), + * swap internal pivot values to ends. + */ + if (great - less > 5 * seventh) { + 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 not inspected ?-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 + dualPivotQuicksort(a, less, great); + } else { // Pivots are equal /* - * Partition degenerates to the traditional 3-way, - * or "Dutch National Flag", partition: + * Partition degenerates to the traditional 3-way + * (or "Dutch National Flag") schema: * * left part center part right part * +----------------------------------------------+ @@ -1774,7 +1937,7 @@ * all in [less, k) == pivot * all in (great, right) > pivot * - * Pointer k is the first index of ?-part + * Pointer k is the first index of not inspected ?-part. */ for (int k = less; k <= great; k++) { float ak = a[k]; @@ -1787,7 +1950,7 @@ a[less] = ak; } less++; - } else { // (a[k] > pivot1) - Move a[k] to right part + } 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 @@ -1800,87 +1963,17 @@ 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; } + 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; + // Sort left and right parts recursively + dualPivotQuicksort(a, left, less - 1); + dualPivotQuicksort(a, great + 1, right); } - - /* - * 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); } /** @@ -1938,7 +2031,7 @@ */ private static void sortNegZeroAndNaN(double[] a, int left, int right) { /* - * Phase 1: Count negative zeros and move NaNs to end of array + * Phase 1: Count negative zeros and move NaNs to end of array. */ final long NEGATIVE_ZERO = Double.doubleToLongBits(-0.0d); int numNegativeZeros = 0; @@ -1956,12 +2049,12 @@ } /* - * Phase 2: Sort everything except NaNs (which are already in place) + * Phase 2: Sort everything except NaNs (which are already in place). */ - doSort(a, left, n); + dualPivotQuicksort(a, left, n); /* - * Phase 3: Turn positive zeros back into negative zeros as appropriate + * Phase 3: Turn positive zeros back into negative zeros. */ if (numNegativeZeros == 0) { return; @@ -2005,51 +2098,68 @@ } /** - * 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. + * Sorts the specified range of the array into ascending order by the + * Dual-Pivot Quicksort algorithm. * - * @param a the array to be sorted, which must not contain -0.0d and 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 doSort(double[] a, int left, int right) { + private static void dualPivotQuicksort(double[] a, int left, int right) { + int length = right - left + 1; + + // Skip trivial arrays + if (length < 2) { + return; + } + // 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]; + if (length < INSERTION_SORT_THRESHOLD) { + if (left > 0) { + /* + * Set negative infinity as a sentinel before the specified + * range of the array, it allows to avoid expensive + * check j >= left on each iteration. + */ + double before = a[left-1];a[left-1] = Double.NEGATIVE_INFINITY; + + for (int j, i = left + 1; i <= right; i++) { + double ai = a[i]; + for (j = i - 1; /* j >= left && */ ai < a[j]; j--) { + a[j + 1] = a[j]; + } + a[j + 1] = ai; } - a[j + 1] = ai; + a[left - 1] = before; + } else { + /* + * For case, when left == 0, traditional (without a sentinel) + * insertion sort, optimized for server VM, is used. + */ + for (int i = 0, j = i; i < right; j = ++i) { + double ai = a[i + 1]; + while (ai < a[j]) { + a[j + 1] = a[j]; + if (j-- == 0) { + break; + } + } + a[j + 1] = ai; + } } - } else { // Use Dual-Pivot Quicksort on large arrays - dualPivotQuicksort(a, left, right); + return; } - } - /** - * 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; + // Inexpensive approximation of one seventh + int seventh = (length >>> 3) + (length >>> 6) + 1; + + // Compute indices of 5 center evenly spaced elements int e3 = (left + right) >>> 1; // The midpoint - int e4 = e3 + sixth; - int e2 = e3 - sixth; + int e2 = e3 - seventh, e1 = e2 - seventh; + int e4 = e3 + seventh, e5 = e4 + seventh; // 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]; + double ae1 = a[e1], ae3 = a[e3], ae5 = a[e5], ae2 = a[e2], ae4 = a[e4]; if (ae1 > ae2) { double t = ae1; ae1 = ae2; ae2 = t; } if (ae4 > ae5) { double t = ae4; ae4 = ae5; ae5 = t; } @@ -2061,39 +2171,40 @@ 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; + a[e1] = ae1; a[e3] = ae3; a[e5] = ae5; a[e2] = ae2; a[e4] = ae4; /* * 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]; + double pivot1 = a[e2]; + double pivot2 = a[e4]; // 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 + int less = left; // The index of the first element of center part + int great = right; // The index before the first element of right part - boolean pivotsDiffer = (pivot1 != pivot2); + if (pivot1 < pivot2) { + /* + * The first and the last 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. + */ + a[e2] = a[less++]; + a[e4] = a[great--]; - if (pivotsDiffer) { /* * Partitioning: * - * left part center part right part - * +------------------------------------------------------------+ - * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 | - * +------------------------------------------------------------+ - * ^ ^ ^ - * | | | - * less k great + * left part center part right part + * +--------------------------------------------------------------+ + * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 | + * +--------------------------------------------------------------+ + * ^ ^ ^ + * | | | + * less k great * * Invariants: * @@ -2101,7 +2212,7 @@ * pivot1 <= all in [less, k) <= pivot2 * all in (great, right) > pivot2 * - * Pointer k is the first index of ?-part + * Pointer k is the first index of not inspected ?-part. */ outer: for (int k = less; k <= great; k++) { @@ -2121,17 +2232,82 @@ 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; } + 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 pivots + dualPivotQuicksort(a, left, less - 2); + dualPivotQuicksort(a, great + 2, right); + + /* + * If center part is too large (comprises > 5/7 of the array), + * swap internal pivot values to ends. + */ + if (great - less > 5 * seventh) { + 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 not inspected ?-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 + dualPivotQuicksort(a, less, great); + } else { // Pivots are equal /* - * Partition degenerates to the traditional 3-way, - * or "Dutch National Flag", partition: + * Partition degenerates to the traditional 3-way + * (or "Dutch National Flag") schema: * * left part center part right part * +----------------------------------------------+ @@ -2147,7 +2323,7 @@ * all in [less, k) == pivot * all in (great, right) > pivot * - * Pointer k is the first index of ?-part + * Pointer k is the first index of not inspected ?-part. */ for (int k = less; k <= great; k++) { double ak = a[k]; @@ -2160,7 +2336,7 @@ a[less] = ak; } less++; - } else { // (a[k] > pivot1) - Move a[k] to right part + } 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 @@ -2173,87 +2349,17 @@ 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; } + 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; + // Sort left and right parts recursively + dualPivotQuicksort(a, left, less - 1); + dualPivotQuicksort(a, great + 1, right); } - - /* - * 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); } /** @@ -2263,7 +2369,7 @@ private static void rangeCheck(int length, int fromIndex, int toIndex) { if (fromIndex > toIndex) { throw new IllegalArgumentException( - "fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")"); + "fromIndex: " + fromIndex + " > toIndex: " + toIndex); } if (fromIndex < 0) { throw new ArrayIndexOutOfBoundsException(fromIndex);