java源码——Array.sort() 排序

java源码 Array.sort()

在学习Array.sort()的排序规则之前应该先了解以下几种排序。

  1. 插入排序及其优化算法
  2. 快速排序及其双轴快速排序算法
  3. Tim排序
  4. 归并排序

源码中,就是这几种排序混合使用。

下文以整形数组为例进行解读。

对传入Array.sort()中的数组,会传入DualPivotQuicksort.sort()方法中实现排序。


//a是数组,0是左边界,a.length-1是右边界,
//后三个参数是关于操作空间的,其存在的实际用途我也不太明白,
//若有大佬晓得,还请指点迷津。
public static void sort(int[] a) {
   
        DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
    }
    

对源码的代码我做了略微的修改,方便阅读,与源码有略微差异

初次判断排序方式

判断数组长度是否达到286,若 length < 286,使用快速排序,否则进行Tim排序检验


//如果排序数组长度小于286,进行快速排序,sort的参数true是表示使用插入排序,false是使用优化版的插入排序。
        if (right - left < QUICKSORT_THRESHOLD) {
   
            sort(arr, left, right, true);
            return arr;
        }

插入排序

在快速排序中若被排序数组段长度小于47,使用插入排序。根据参数leftmost是否是true决定用普通插入排序还是优化后的插入排序


//插入排序
        if (length < INSERTION_SORT_THRESHOLD) {
            //插入排序
            if (leftmost) {
                for (int i = left, j = i; i < right; j = ++i) {
                    int ai = arr[i + 1];
                    while (ai < arr[j]) {
                        arr[j + 1] = arr[j];
                        if (j-- == left) {
                            break;
                        }
                    }
                    arr[j + 1] = ai;
                }
            }
            //优化的插入排序
            else {

                //跳过升序阶段
                do {
                    if (left >= right) {
                        return;
                    }
                } while (arr[++left] >= arr[left - 1]);

                /**
                 * 插入排序的优化算法
                 * 一次性进行两个数值的排序,
                 * 将两个数值进行比较,选出最大的值作为标志数和左边的数值依次进行对比,被比较的数若大于标志数,该数向右移动两个位置,
                 * 直到该数小于标志数,将标志数放在小于标志数的数的右边第二位,将另一个数作为标志数向左比较,被比较的数若大于标志数,该数向右移动一个位置,
                 * 直到该数小于标志数,将标志数放在小于标志数的数的右边第一位。
                 * */
                for (int i = left; ++left <= right; i = ++left) {
                    int a1 = arr[i], a2 = arr[left];
                    if (a1 < a2) {
                        a2 = a1;
                        a1 = arr[left];
                    }
                    while (a1 < arr[--i]) {
                        arr[i + 2] = arr[i];
                    }
                    arr[++i + 1] = a1;
                    while (a2 < arr[--i]) {
                        arr[i + 1] = arr[i];
                    }
                    arr[i + 1] = a2;
                }
                //上述排序是成对排序,若数组数是单数,则需要对数组最后一位数排序
                int last = arr[right];
                while (last < arr[--right]) {
                    arr[right + 1] = arr[right];
                }
                arr[right + 1] = last;
            }
            return;
        }

快速排序

对于java中的快速排序,数组长度要超过47,然后设置五个点位,分别为e1,e2,e3,e4,e5。并且 a[e1]<=a[e2]<=a[e3]<=a[e4]<=a[e5];

若是五个点位上的数不相等,即 a[e1] != a[e2] && a[e2] != a[e3] && a[e3] != a[e4] && a[e4] != a[e5] ,则使用双轴快速排序。以e2为左轴,e4为右轴。

若是五个点位上有数相等,则使用单轴快速排序。即以e3为轴。


//快速排序
        //数组长度除以7 ,即 length / 7;
        int seventh = (length >> 3) + (length >> 6) + 1;

        int e3 = (right + left) >>> 1;
        int e2 = e3 - seventh;
        int e4 = e3 + seventh;
        int e1 = e2 - seventh;
        int e5 = e4 + seventh;

        //保证 arr[e1] <= arr[e2] <= arr[e3] <= arr[e4] <= arr[e5]
        if (arr[e2] < arr[e1]) {
   
            int t = arr[e2]; arr[e2] = arr[e1]; arr[e1] = t;
        }

        if (arr[e3] < arr[e2]) {
   
            int t = arr[e3]; arr[e3] = arr[e2]; arr[e2] = t;
            if (t < arr[e1]) {
   
                arr[e2] = arr[e1]; arr[e1] = t;
            }
        }
        if (arr[e4] < arr[e3]) {
   
            int t = arr[e4]; arr[e4] = arr[e3]; arr[e3] = t;
            if (t < arr[e2]) {
   
                arr[e3] = arr[e2]; arr[e2] = t;
                if (t < arr[e1]) {
   
                    arr[e2] = arr[e1]; arr[e1] = t;
                }
            }
        }
        if (arr[e5] < arr[e4]) {
   
            int t = arr[e5]; arr[e5] = arr[e4]; arr[e4] = t;
            if (t < arr[e3]) {
   
                arr[e4] = arr[e3]; arr[e3] = t;
                if (t < arr[e2]) {
   
                    arr[e3] = arr[e2]; arr[e2] = t;
                    if (t < arr[e1]) {
   
                        arr[e2] = arr[e1]; arr[e1] = t;
                    }
                }
            }
        }

        //建立左右指针
        int less = left;
        int great = right;

        //如果arr[e1] < arr[e2] < arr[e3] < arr[e4] < arr[e5],进行双轴排序
        if (arr[e1] != arr[e2] && arr[e2] != arr[e3] && arr[e3] != arr[e4] && arr[e4] != arr[e5]) {
   
            //建立左右轴
            int pivot1 = arr[e2];
            int pivot2 = arr[e4];

            arr[e2] = arr[left];
            arr[e4] = arr[right];

            while (pivot1 > arr[++less]) ;
            while (pivot2 < arr[--great]) ;

            /*
             * 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 - 1; ++k <= great; ) {
   
                int ak = arr[k];
                if (ak < pivot1) {
   
                    arr[k] = arr[less];
                    arr[less] = ak;
                    less++;
                } else if (ak > pivot2) {
   
                    while (pivot2 < arr[great]) {
   
                        if (great-- == k) {
   
                            break outer;
                        }
                    }
                    if (pivot1 > arr[great]) {
   
                        arr[k] = arr[less];
                        arr[less] = arr[great];
                        less++;
                    } else {
   
                        arr[k] = arr[great];
                    }
                    arr[great] 
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值