集合中排序 Collections.sort方法源码分析

集合中排序 Collections.sort方法源码分析

集合排序有Collections.sort(List list) 和 Collections.sort(List list, Comparator<? super T> c)两种排序方法。

  1. Collections.sort(List list)
public static <T extends Comparable<? super T>> void sort(List<T> list) {
    list.sort(null);
}
  1. Collections.sort(List list, Comparator<? super T> c)
public static <T> void sort(List<T> list, Comparator<? super T> c) {
    list.sort(c);
}

其实我们可以看到这两种方法都是调用的list.sort()方法,只是传参不同;第一种没有Comparator比较器,所以参数为null;第二种有Comparator以将比较器传入。

list.sort(Comparator<? super E> c)方法

这个方法是将集合转换为Object数组a,然后调用Arrays.sort(T[] a, Comparator<? super T> c)。

default void sort(Comparator<? super E> c) {
    Object[] a = this.toArray();
    Arrays.sort(a, (Comparator) c);
    //进行迭代遍历,将排序好的a数组设置到集合中
    ListIterator<E> i = this.listIterator();
    for (Object e : a) {
        i.next();
        i.set((E) e);
    }
}

Arrays.sort(T[] a, Comparator<? super T> c)方法:

public static <T> void sort(T[] a, Comparator<? super T> c) {
    //当传入的比较器为空时,执行 java自带的sort(a);
    if (c == null) {
        sort(a);
    } else {
        //userRequested用户请求使用。这里是老版本jdk1.5的,将来会被删除,可以忽略
        if (LegacyMergeSort.userRequested)
            legacyMergeSort(a, c);
        else
            //使用指定的比较器
            TimSort.sort(a, 0, a.length, c, null, 0, 0);
    }
}

提一下 **legacyMergeSort(a, c);**将在将来的版本中删除。

//将在将来的版本中删除。
private static <T> void legacyMergeSort(T[] a, Comparator<? super T> c) {
        T[] aux = a.clone();
        if (c==null)
            mergeSort(aux, a, 0, a.length, 0);
        else
            mergeSort(aux, a, 0, a.length, 0, c);
    }

进入sort(Object[] a)方法

public static void sort(Object[] a) {
    if (LegacyMergeSort.userRequested)
        legacyMergeSort(a);
    else
        //进入方法
        ComparableTimSort.sort(a, 0, a.length, null, 0, 0);
}

再进入ComparableTimSort.sort方法

  private static final int MIN_MERGE = 32;
/**
*使用给定的工作空间数组切片对给定范围排序
*尽可能用于临时存储。此方法旨在
*执行后从公共方法(类数组中)调用
*任何必要的数组边界检查并将参数扩展到
*所需表格。
*/
static void sort(Object[] a, int lo, int hi, Object[] work, int workBase, int workLen) {
        assert a != null && lo >= 0 && lo <= hi && hi <= a.length;  
		int nRemaining  = hi - lo;
    //数组长度nRemaining小于等于1,无需排序
    if (nRemaining < 2)
        return;  
	
	// If array is small, do a "mini-TimSort" with no merges
    // 数组长度小于32,使用binarySort 二分法排序
    if (nRemaining < MIN_MERGE) {
        int initRunLen = countRunAndMakeAscending(a, lo, hi);
        binarySort(a, lo, hi, lo + initRunLen);
        return;
    }

    /**
     * 从左到右在阵列上行进一次,寻找自然路线,将短期自然跑步延伸到minRun元素,
     * 并合并运行保持堆栈不变。
     */
    ComparableTimSort ts = new ComparableTimSort(a, work, workBase, workLen);
    //选取分块大小
    int minRun = minRunLength(nRemaining);
    //TimSort:先扫描找到已经排好的序列,然后再用刚才的mini-TimSort,然后合并
    do {
        // 确定下一次运行
        int runLen = countRunAndMakeAscending(a, lo, hi);

        // 如果运行长度短,则扩展到min(minRun,nRemaining),还是使用二分法排序
        if (runLen < minRun) {
            int force = nRemaining <= minRun ? nRemaining : minRun;
            binarySort(a, lo, lo + force, lo + runLen);
            runLen = force;
        }

        // Push run onto pending-run stack, and maybe merge
        ts.pushRun(lo, runLen);
        ts.mergeCollapse();

        // Advance to find next run
        lo += runLen;
        nRemaining -= runLen;
    } while (nRemaining != 0);

    // Merge all remaining runs to complete sort
    assert lo == hi;
    ts.mergeForceCollapse();
    assert ts.stackSize == 1;
}

上面就是没有传比较器而走默认的sort()方法的方式

当代码执行指定比较器时进入TimSort.sort方法时,其实可以发现ComparableTimSort.sort和TimSort.sort是一样的,官方说ComparableTimSort是TimSort副本。因为传入参数不同,最终执行了我们指定的比较器结果

Timsort是结合了合并排序(merge sort)和插入排序(insertion sort)而得出的排序算法,它在现实中有很好的效率。该算法找到数据中已经排好序的块-分区,每一个分区叫一个run,然后按规则合并这些run。Pyhton自从2.3版以来一直采用Timsort算法排序,现在Java SE7和Android也采用Timsort算法对数组排序。

总结

1.使用Collections.sort(List list)或者Collections.sort(List list, Comparator<? super T> c)方法,他们执行的都是同一个sort(Comparator<? super E> c)。

2.进入sort将集合转为数组a,调用Arrays.sort方法进行排序。然后排序好的数组,复制到集合中去。

3.进入Arrays.sort(a, (Comparator) c)

  • 无比较器:

    • Arrays.sort:经过判断无比较器,执行默认的sort(a);
    • 进入sort(a):进行判断,执行ComparableTimSort.sort()方法,这个方法和TimSort.sort()是一样的,只是有传无比较器的区别,默认的就是按照小到大排序或者实现的Comparator接口重写方法排序;
  • 有比较器:

    • Arrays.sort:经过判断有比较器,执行TimSort.sort()方法,按照我们指定的排序进行排序。

新手学员,如有错误请指正

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

别来无恙blwy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值