jdk1.8 DualPivotQuicksort类简析

DualPivotQuicksort类主要实现了jdk的排序算法

int型数组

length<47时用插入排序(涉及到pair insertion),47<=length<286,用快排,length>=286时用归并排序

byte、short、char型数据用计数排序。

 

此处主要分析针对int数组的sort方法(该方法实现了插入排序和快排部分),声明如下:

/**

* Sorts the specified range of the array by Dual-Pivot Quicksort.

*

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

* @param leftmost indicates if this part is the leftmost in the range

*/

private static void sort(int[] a, int left, int right, boolean leftmost) {}

此sort中插入排序略过,主要分析快排的实现。

以数组的median值为参考,在其附近以length/7(用length>>3+length>>6+1逼近)为间隔依次取e1、e2、e3(median)、e4、e5并对a[e1]、a[e2] 、a[e3] 、a[e4] 、a[e5]插入排序。

 

1)若以e1、e2、e3、e4、e5为index的值互不相等,则使用双轴快排:

选两个枢纽元pivot1(a[e2])和pivot2(a[e4]),将数组分成如下3部分:

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

分割完成后对left part和right part再调用此sort方法。

            long pivot1 = a[e2];
            long pivot2 = a[e4];
            /*
             * 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[left];
            a[e4] = a[right];
            /*
             * Skip elements, which are less or greater than pivot values.
             */
            while (a[++less] < pivot1);
            while (a[--great] > pivot2);
            outer:
            for (int k = less - 1; ++k <= great; ) {
                long ak = a[k];
                if (ak < pivot1) { // Move a[k] to left part
                    a[k] = a[less];
                    /*
                     * Here and below we use "a[i] = b; i++;" instead
                     * of "a[i++] = b;" due to performance issue.
                     */
                    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[great] <= pivot2
                        a[k] = a[less];
                        a[less] = a[great];
                        ++less;
                    } else { // pivot1 <= a[great] <= pivot2
                        a[k] = a[great];
                    }
                    /*
                     * Here and below we use "a[i] = b; i--;" instead
                     * of "a[i--] = b;" due to performance issue.
                     */
                    a[great] = ak;
                    --great;
                }
            }

            // 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
            sort(a, left, less - 2, leftmost);
            sort(a, great + 2, right, false);

center part如果占据整个数组的4/7(less < e1 && e5 < 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.
                 */

然后再对center part调用sort方法

                /*
                 * Skip elements, which are equal to pivot values.
                 */
                while (a[less] == pivot1) {
                    ++less;
                }

                while (a[great] == pivot2) {
                    --great;
                }
                outer:
                for (int k = less - 1; ++k <= great; ) {
                    long ak = a[k];
                    if (ak == pivot1) { // Move a[k] to left part
                        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[great] < pivot2
                            a[k] = a[less];
                            /*
                             * Even though a[great] equals to pivot1, the
                             * assignment a[less] = pivot1 may be incorrect,
                             * if a[great] and pivot1 are floating-point zeros
                             * of different signs. Therefore in float and
                             * double sorting methods we have to use more
                             * accurate assignment a[less] = a[great].
                             */
                            a[less] = pivot1;
                            ++less;
                        } else { // pivot1 < a[great] < pivot2
                            a[k] = a[great];
                        }
                        a[great] = ak;
                        --great;
                    }
                }
            }

            // Sort center part recursively
            sort(a, less, great, false);

 

2) 若以e1、e2、e3、e4、e5为index的值有两个以上相等,则使用单个枢纽元(pivot取a[e3])的三路方案:

            /*
             * Partitioning degenerates to the traditional 3-way
             * (or "Dutch National Flag") schema:
             *
             *   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.
             */

分割后对left part和right part再调用此sort方法。

            long pivot = a[e3];
            for (int k = less; k <= great; ++k) {
                if (a[k] == pivot) {
                    continue;
                }
                long ak = a[k];
                if (ak < pivot) { // Move a[k] to left part
                    a[k] = a[less];
                    a[less] = ak;
                    ++less;
                } else { // a[k] > pivot - Move a[k] to right part
                    while (a[great] > pivot) {
                        --great;
                    }
                    if (a[great] < pivot) { // a[great] <= pivot
                        a[k] = a[less];
                        a[less] = a[great];
                        ++less;
                    } else { // a[great] == pivot
                        /*
                         * Even though a[great] equals to pivot, the
                         * assignment a[k] = pivot may be incorrect,
                         * if a[great] and pivot are floating-point
                         * zeros of different signs. Therefore in float
                         * and double sorting methods we have to use
                         * more accurate assignment a[k] = a[great].
                         */
                        a[k] = pivot;
                    }
                    a[great] = ak;
                    --great;
                }
            }

            /*
             * Sort left and right parts recursively.
             * All elements from center part are equal
             * and, therefore, already sorted.
             */
            sort(a, left, less - 1, leftmost);
            sort(a, great + 1, right, false);

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值