Java8 Collections.sort()的底层源码分析

JDK版本:1.8

IDEA版本:2021.2.3

众所周知,List集合可以像数组一样排序,那么接下来查看逐个方法,探究其底层实现

首先建一个简单的Demo

public static void main(String[] args){
    List<Integer>list=new ArrayList<>();
    Collections.sort(list);
}

1. 点击 sort 方法,跳转至 Collections.java 

首先来看注释:

/*
* Sorts the specified list into ascending order, according to the natural ordering of its * * elements. All elements in the list must implement the Comparable interface. Furthermore, * all elements in the list must be mutually comparable (that is, e1.compareTo(e2) must not * throw a ClassCastException for any elements e1 and e2 in the list).
* This sort is guaranteed to be stable: equal elements will not be reordered as a result of * the sort.
* The specified list must be modifiable, but need not be resizable.
*/

通过阅读上方的注释可知,传入的泛型必须实现Comparable,并且元素之间可比较,否则抛出ClassCastException

@SuppressWarnings("unchecked")
public static <T extends Comparable<? super T>> void sort(List<T> list) {
    list.sort(null);
}

通过源码可见,其实调用的是List的sort()方法,所以这个方法的作用应该是限制泛型必须实现Comparable接口,再进行下一步的排序。

点击 Comparable 查看该接口:

public interface Comparable<T> {
    public int compareTo(T o);
}

2. 点击 list.sort(null),进入 List.java

@SuppressWarnings({"unchecked", "rawtypes"})
default void sort(Comparator<? super E> c) {
    Object[] a = this.toArray();
    Arrays.sort(a, (Comparator) c);
    ListIterator<E> i = this.listIterator();
    for (Object e : a) {
        i.next();
        i.set((E) e);
    }
}

显然,基本思路是将 List 集合通过 toArray() 方法转化为数组,再调用 Arrays.sort() 方法进行排序。最后遍历数组,使用迭代器指针重新设置 List 集合中的值。

3. 探究此处调用的 Arrays.sort() 

注意此处的Arrays.sort()并非直接传入的数组的那个方法,这里调用的是两个形参的方法,它们的底层实现略有区别。

点击 Arrays.sort() 方法,跳转到 Arrays.java 

/*
Implementation note: This implementation is a stable, adaptive, iterative mergesort that requires far fewer than n lg(n) comparisons when the input array is partially sorted,while offering the performance of a traditional mergesort when the input array is randomly ordered. If the input array is nearly sorted, the implementation requires approximately n comparisons. Temporary storage requirements vary from a small constant for nearly sorted input arrays to n/2 object references for randomly ordered input arrays.
The implementation takes equal advantage of ascending and descending order in its input array, and can take advantage of ascending and descending order in different parts of the same input array. It is well-suited to merging two or more sorted arrays: simply concatenate the arrays and sort the resulting array.
*/

根据这个注释可知,这里的 sort()方法主要采用归并排序

public static <T> void sort(T[] a, Comparator<? super T> c) {
    if (c == null) {
        sort(a);
    } else {
        if (LegacyMergeSort.userRequested)
            legacyMergeSort(a, c);
        else
            TimSort.sort(a, 0, a.length, c, null, 0, 0);
    }
}

形参c为空,因此满足第一个if条件,再进入 sort() 方法

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

此处的 LegacyMergeSort.userRequested 主要作用是兼容版本,接下来走 legacyMergeSort(a) 

private static void legacyMergeSort(Object[] a) {
    Object[] aux = a.clone();
    mergeSort(aux, a, 0, a.length, 0);
}
    private static void mergeSort(Object[] src,
                                  Object[] dest,
                                  int low,
                                  int high,
                                  int off) {
        int length = high - low;

        // Insertion sort on smallest arrays
        if (length < INSERTIONSORT_THRESHOLD) {
            for (int i=low; i<high; i++)
                for (int j=i; j>low &&
                         ((Comparable) dest[j-1]).compareTo(dest[j])>0; j--)
                    swap(dest, j, j-1);
            return;
        }

        // Recursively sort halves of dest into src
        int destLow  = low;
        int destHigh = high;
        low  += off;
        high += off;
        int mid = (low + high) >>> 1;
        mergeSort(dest, src, low, mid, -off);
        mergeSort(dest, src, mid, high, -off);

        // If list is already sorted, just copy from src to dest.  This is an
        // optimization that results in faster sorts for nearly ordered lists.
        if (((Comparable)src[mid-1]).compareTo(src[mid]) <= 0) {
            System.arraycopy(src, low, dest, destLow, length);
            return;
        }

        // Merge sorted halves (now in src) into dest
        for(int i = destLow, p = low, q = mid; i < destHigh; i++) {
            if (q >= high || p < mid && ((Comparable)src[p]).compareTo(src[q])<=0)
                dest[i] = src[p++];
            else
                dest[i] = src[q++];
        }
    }
    private static void swap(Object[] x, int a, int b) {
        Object t = x[a];
        x[a] = x[b];
        x[b] = t;
    }

其中注意一个常量:

private static final int INSERTIONSORT_THRESHOLD = 7;

这说明当数组长度小于7时,只走插入排序,否则执行归并排序

这里再重复一次,Collections.sort()调用的 Arrays.sort() 有两个形参:

T[] a 和 Comparator<? super T> c

不同于平时直接调用的 Arrays.sort() ,因此不必奇怪为什么不是快速排序,后面有时间再开一贴,剖析 Arrays.sort() 的源码。

复杂度分析 

List 集合长度< 7 时:

平均时间复杂度:O(n^2)
最佳时间复杂度:O(n)
最差时间复杂度:O(n^2)
空间复杂度:O(n)
稳定性:稳定

List 集合长度 >= 7 时:

平均时间复杂度:O(nlogn)
最佳时间复杂度:O(n)
最差时间复杂度:O(nlogn)
空间复杂度:O(n)
稳定性:稳定

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值