JDK1.8中的数组排序

Array.sort()

核心思路

根据不同的情况,选择不同的排序算法。

1、当需要排列的元素较少的时候,采用普通的插入排序

当被排序的数组长度小于47但排序不是从数组起始位置开始的时候,那么就会选择哨兵插入排序的方式进行排序。
这种情况主要是当sort被双基准快排递归调用的时候才会使用

2、如果元素较多,大于插入排序的阈值,但是小于归并排序的阈值,这时采用快速排序
在进行快排之前,首先会将这个不长不断的数组按照1/7的长度划分,最后划分后的结果为:

        // Inexpensive approximation of length / 7
        int seventh = (length >> 3) + (length >> 6) + 1;

        /*
         * Sort five evenly spaced elements around (and including) the
         * center element in the range. These elements will be used for
         * pivot selection as described below. The choice for spacing
         * these elements was empirically determined to work well on
         * a wide variety of inputs.
         */
        int e3 = (left + right) >>> 1; // The midpoint
        int e2 = e3 - seventh;
        int e1 = e2 - seventh;
        int e4 = e3 + seventh;
        int e5 = e4 + seventh;

然后对这5个划分点进行排序:
2.1 如果这五个划分点的数据俩俩各不相同,则以第一个划分点和最后一个划分点作为基准点,采用双基准快排
采用双基准快排也有优化的地方,如果中间的元素过多(超过整个排序部分的七分之四),将会针对这一区间内的重复键进行优化。
与基准1和基准2 相同的键将会被分到前后两个分区,并会被从接下来要继续递归排序的中间分区中剔除,尽可能减少了中间分区的大小。

                for (int k = less - 1; ++k <= great; ) {
                    int 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;
                    }
                }

2.2 如果这五个划分点有相同的情况,则采用三路快排。
3、如果数组的长度超过了快排的阈值
首先进行有序性的判断,判断这个数组是否是基本有序
将有序部分中断处的位置记录下来,如果中断个数大于某个阈值则判断为无序,反之有序。
3.1 如果是基本有序,则采用归并方式排序,这里会按照刚才记录的有序部分的中断点作为归并点。
3.2 如果判定为无序,则依然采用快排。

Collections.sort()

TimSort

Arrays.parallelSort()

posted @ 2020-11-26 18:57  刃牙  阅读(1255)  评论(0编辑  收藏  举报