Collections.sort()源码

Collections.sort()方法

    Collections.sort()方法会将传来的list转换为数组,调用Arrays.sort()方法。

Arrays.sort

    public static <T> void sort(T[] a, Comparator<? super T> c) {
        if (c == null) {
            //没有比较器,会使用对象自身的,对象a肯定可以转换为Comparator类,两者区别不大
            sort(a);
        } else {
            if (Arrays.LegacyMergeSort.userRequested)
                //已经确定后续将会取消这个方法
                legacyMergeSort(a, c);
            else
                TimSort.sort(a, 0, a.length, c, null, 0, 0);
        }
    }

sort

    static <T> void sort(T[] a, int lo, int hi, Comparator<? super T> c,
                         T[] work, int workBase, int workLen) {
        int nRemaining = hi - lo;
        if (nRemaining < 2)
            return;  // Arrays of size 0 and 1 are always sorted

        //长度小于32,可以简单处理
        if (nRemaining < MIN_MERGE) {
            //查询a的初始最长有序的长度initRunLen,如果是降序就改为升序。
            //现在a已经变为前initRunLen个是升序排序,后面都是无序的。
            int initRunLen = countRunAndMakeAscending(a, lo, hi, c);
            //通过二分插入排序方法,对数组排序
            binarySort(a, lo, hi, lo + initRunLen, c);
            return;
        }

        TimSort<T> ts = new TimSort<>(a, c, work, workBase, workLen);
        int minRun = minRunLength(nRemaining);
        do {
            //计算最小处理长度minRun,minRun数值会在16~32之间。
            //这样a数组就可以分为若干个长度为minRun的小段,每次循环处理
            //由于是数组只需要存储minRun和第几次就行,不需要真的分段。
            int runLen = countRunAndMakeAscending(a, lo, hi, c);

            //不满足条件时,说明数组前minRun个元素,已经排好序,不需要多余操作
            if (runLen < minRun) {
                //如果要处理的数组长度已经不足minRun,直接处理剩余的数据
                int force = nRemaining <= minRun ? nRemaining : minRun;
                //现在要排序的数组一段是前runLen个是升序排序,后面无序。
                binarySort(a, lo, lo + force, lo + runLen, c);
                runLen = force;
            }

            //入栈每一段的起始位置和长度,相当于将这一小段有序数据入栈。
            ts.pushRun(lo, runLen);
            //对入栈的有序数据段进行合并
            ts.mergeCollapse();

            lo += runLen;
            nRemaining -= runLen;
        } while (nRemaining != 0);

        assert lo == hi;
        //将剩余的数据段合并
        ts.mergeForceCollapse();
        assert ts.stackSize == 1;
    }

countRunAndMakeAscending

    /**
     * 查询a的初始最长有序的长度initRunLen,如果是降序就改为升序。
     *
     * @param a  目标数组
     * @param lo 处理数据的起始位置
     * @param hi 处理数据的结束位置
     * @param c  比较器
     */
    private static <T> int countRunAndMakeAscending(T[] a, int lo, int hi,
                                                    Comparator<? super T> c) {
        assert lo < hi;
        int runHi = lo + 1;
        if (runHi == hi)
            return 1;

        if (c.compare(a[runHi++], a[lo]) < 0) { // Descending
            //找到最长的有序数据段
            while (runHi < hi && c.compare(a[runHi], a[runHi - 1]) < 0) {
                runHi++;
            }
            //改为升序
            reverseRange(a, lo, runHi);
        } else {                              // Ascending
            //找到最长的有序数据段
            while (runHi < hi && c.compare(a[runHi], a[runHi - 1]) >= 0)
                runHi++;
        }
        return runHi - lo;
    }

binarySort

    //通过二分插入排序方法,对数组排序
    private static <T> void binarySort(T[] a, int lo, int hi, int start,
                                       Comparator<? super T> c) {
        if (start == lo)
            start++;
        for (; start < hi; start++) {
            T pivot = a[start];

            // Set left (and right) to the index where a[start] (pivot) belongs
            int left = lo;
            int right = start;
            assert left <= right;
            /*
             * Invariants:
             *   pivot >= all in [lo, left).
             *   pivot <  all in [right, start).
             */
            while (left < right) {
                int mid = (left + right) >>> 1;
                if (c.compare(pivot, a[mid]) < 0)
                    right = mid;
                else
                    left = mid + 1;
            }
            assert left == right;

            int n = start - left;  // The number of elements to move
            // Switch is just an optimization for arraycopy in default case
            switch (n) {
                case 2:
                    a[left + 2] = a[left + 1];
                case 1:
                    a[left + 1] = a[left];
                    break;
                default:
                    System.arraycopy(a, left, a, left + 1, n);
            }
            a[left] = pivot;
        }
    }

minRunLength

    /**
     *  If n < MIN_MERGE, return n (it's too small to bother with fancy stuff).
     *  Else if n is an exact power of 2, return MIN_MERGE/2.
     *  Else return an int k, MIN_MERGE/2 <= k <= MIN_MERGE, such that n/k
     *   is close to, but strictly less than, an exact power of 2.
     */
    private static int minRunLength(int n) {
        assert n >= 0;
        int r = 0;      // Becomes 1 if any 1 bits are shifted off
        // MIN_MERGE 默认为32
        while (n >= MIN_MERGE) {
            r |= (n & 1);
            n >>= 1;
        }
        return n + r;
    }

mergeCollapse

    private void mergeCollapse() {
        //倒数第一段为最新入栈的数据段
        while (stackSize > 1) {
            int n = stackSize - 2;
            //如果栈长大于3,并且倒数第三段的长度小于等于倒数第二段的长度和倒数第一段的长度之和
            if (n > 0 && runLen[n - 1] <= runLen[n] + runLen[n + 1]) {
                if (runLen[n - 1] < runLen[n + 1])
                    //倒数第三段的长度小于倒数第一段的长度
                    //也就是说倒数第二段的长度不为0,就会把倒数第三段和倒数第二段合并
                    n--;
                mergeAt(n);
            } else if (runLen[n] <= runLen[n + 1]) {
                //倒数第二段数据的长度小于等于倒数第一段的数据长度,就会把倒数第二段和倒数第一段倒数第一段合并
                mergeAt(n);
            } else {
                break; // Invariant is established
            }
        }
    }

mergeAt

    private void mergeAt(int i) {
        int base1 = runBase[i];
        int len1 = runLen[i];
        int base2 = runBase[i + 1];
        int len2 = runLen[i + 1];

        //新合并数据段的长度改为两个数据之和,起始位置不需要改变。
        runLen[i] = len1 + len2;
        if (i == stackSize - 3) {
            //如果是倒数第三段和倒数第二段合并,最后一段前面少了一个数据段,所以把最后一段的起始位置和长度,全部前移一位。
            runBase[i + 1] = runBase[i + 2];
            runLen[i + 1] = runLen[i + 2];
        }
        stackSize--;

        /*
         * Find where the first element of run2 goes in run1. Prior elements
         * in run1 can be ignored (because they're already in place).
         */
        int k = gallopRight(a[base2], a, base1, len1, 0, c);
        assert k >= 0;
        base1 += k;
        len1 -= k;
        //修改后的第一段如果没有数据了,这两段的合并就完成了
        if (len1 == 0)
            return;

        /*
         * Find where the last element of run1 goes in run2. Subsequent elements
         * in run2 can be ignored (because they're already in place).
         */
        len2 = gallopLeft(a[base1 + len1 - 1], a, base2, len2, len2 - 1, c);
        //修改后的第二段如果没有数据了,这两段的合并就完成了
        if (len2 == 0)
            return;

        if (len1 <= len2)
            mergeLo(base1, len1, base2, len2);
        else
            mergeHi(base1, len1, base2, len2);
    }

gallopRight

    /*
     * Find where the first element of run2 goes in run1. Prior elements
     * in run1 can be ignored (because they're already in place).
     */
    private static <T> int gallopRight(T key, T[] a, int base, int len,
                                       int hint, Comparator<? super T> c) {
        assert len > 0 && hint >= 0 && hint < len;

        int ofs = 1;
        int lastOfs = 0;
        if (c.compare(key, a[base + hint]) < 0) {
            这个时候其实已经可以返回0
            // Gallop left until a[b+hint - ofs] <= key < a[b+hint - lastOfs]
            int maxOfs = hint + 1;
            while (ofs < maxOfs && c.compare(key, a[base + hint - ofs]) < 0) {
                lastOfs = ofs;
                ofs = (ofs << 1) + 1;
                if (ofs <= 0)   // int overflow
                    ofs = maxOfs;
            }
            if (ofs > maxOfs)
                ofs = maxOfs;

            // Make offsets relative to b
            int tmp = lastOfs;
            lastOfs = hint - ofs;
            ofs = hint - tmp;
        } else { 
            int maxOfs = len - hint;
            while (ofs < maxOfs && c.compare(key, a[base + hint + ofs]) >= 0) {
                lastOfs = ofs;
                //增加ofs,循环尝试
                ofs = (ofs << 1) + 1;
                if (ofs <= 0)   // int overflow
                    ofs = maxOfs;
            }
            //防止溢出
            if (ofs > maxOfs)
                ofs = maxOfs;

            // Make offsets relative to b
            lastOfs += hint;
            ofs += hint;
        }
        /*
         * Now a[b + lastOfs] <= key < a[b + ofs], so key belongs somewhere to
         * the right of lastOfs but no farther right than ofs.  Do a binary
         * search, with invariant a[b + lastOfs - 1] <= key < a[b + ofs].
         */
        lastOfs++;
        while (lastOfs < ofs) {
            int m = lastOfs + ((ofs - lastOfs) >>> 1);

            if (c.compare(key, a[base + m]) < 0)
                ofs = m;          // key < a[b + m]
            else
                lastOfs = m + 1;  // a[b + m] <= key
        }
        return ofs;
    }

mergeLo

    private void mergeLo(int base1, int len1, int base2, int len2) {
        //这两段数据一定是 1头>2头 和 1尾>2所有 2头最小

        // Copy first run into temp array
        T[] a = this.a; // For performance
        T[] tmp = ensureCapacity(len1);
        int cursor1 = tmpBase; // Indexes into tmp array
        int cursor2 = base2;   // Indexes int a
        int dest = base1;      // Indexes int a
        System.arraycopy(a, base1, tmp, cursor1, len1);

        // Move first element of second run and deal with degenerate cases
        a[dest++] = a[cursor2++];
        //如果第二段只有这一个数据,将tmp中的数据复制到原先数据段中的前一位和并就完成了。
        if (--len2 == 0) {
            System.arraycopy(tmp, cursor1, a, dest, len1);
            return;
        }
        //如果第一段的只有一个,已经确定这个数据最小
        //将第一段的数据全部后移一位,把第二段唯一的数据放到最前面,和并就完成了。
        if (len1 == 1) {
            System.arraycopy(a, cursor2, a, dest, len2);
            a[dest + len2] = tmp[cursor1]; // Last elt of run 1 to end of merge
            return;
        }

        Comparator<? super T> c = this.c;  // Use local variable for performance
        int minGallop = this.minGallop;    //  "    "       "     "      "
        outer:
        while (true) {
            int count1 = 0; // Number of times in a row that first run won
            int count2 = 0; // Number of times in a row that second run won

            do {
                assert len1 > 1 && len2 > 0;
                if (c.compare(a[cursor2], tmp[cursor1]) < 0) {
                    a[dest++] = a[cursor2++];
                    count2++;
                    count1 = 0;
                    if (--len2 == 0)
                        break outer;
                } else {
                    a[dest++] = tmp[cursor1++];
                    count1++;
                    count2 = 0;
                    if (--len1 == 1)
                        break outer;
                }
            } while ((count1 | count2) < minGallop);//连续同一侧拷贝多次,就要查询是否可以批量拷贝

            /*
             * One run is winning so consistently that galloping may be a
             * huge win. So try that, and continue galloping until (if ever)
             * neither run appears to be winning consistently anymore.
             */
            do {
                assert len1 > 1 && len2 > 0;
                count1 = gallopRight(a[cursor2], tmp, cursor1, len1, 0, c);
                if (count1 != 0) {
                    //将符合要求的数据批量复制到待处理数组上去
                    System.arraycopy(tmp, cursor1, a, dest, count1);
                    dest += count1;
                    cursor1 += count1;
                    len1 -= count1;
                    if (len1 <= 1) // len1 == 1 || len1 == 0
                        break outer;
                }
                a[dest++] = a[cursor2++];
                if (--len2 == 0)
                    break outer;

                count2 = gallopLeft(tmp[cursor1], a, cursor2, len2, 0, c);
                if (count2 != 0) {
                    System.arraycopy(a, cursor2, a, dest, count2);
                    dest += count2;
                    cursor2 += count2;
                    len2 -= count2;
                    if (len2 == 0)
                        break outer;
                }
                a[dest++] = tmp[cursor1++];
                if (--len1 == 1)
                    break outer;
                minGallop--;
            } while (count1 >= MIN_GALLOP | count2 >= MIN_GALLOP);
            if (minGallop < 0)
                minGallop = 0;
            minGallop += 2;  // Penalize for leaving gallop mode
        }  // End of "outer" loop
        this.minGallop = minGallop < 1 ? 1 : minGallop;  // Write back to field

        if (len1 == 1) {
            //因为有个前提就是第一个数据段的最后一个数字是最大的
            //将第二个数据段剩余的数据前移以为
            System.arraycopy(a, cursor2, a, dest, len2);
            //将第一个数据段的最后一位放在最后
            a[dest + len2] = tmp[cursor1]; //  Last elt of run 1 to end of merge
        } else if (len1 == 0) {
            throw new IllegalArgumentException(
                    "Comparison method violates its general contract!");
        } else {
            //第一个数据段剩余的数据已经是最大了,按顺序放在最后就行
            System.arraycopy(tmp, cursor1, a, dest, len1);
        }
    }

mergeForceCollapse

    //如果最后剩余栈长大于1,就倒着循环所有数据段,进行合并。
    //原则上是让较短的先合并。
    private void mergeForceCollapse() {
        while (stackSize > 1) {
            int n = stackSize - 2;
            if (n > 0 && runLen[n - 1] < runLen[n + 1])
                n--;
            mergeAt(n);
        }
    }
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值