【萌姐讲底层原理】Arrays.sort & Collections.sort 底层原理

where

Arrays和Collections 是JDK 中能实现排序的两个工具类,都来自java.util工具包

what

Arrays.sort 主要用于数组排序,包括基本类型的数组和对象数组。 Collections.sort 对List等集合类进行排序.

底层实现(jdk1.8版本)

Collections.sort 方法调用了list.sort方法

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

list.sort方法 调用了Arrays.sort 方法

 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);
        }
    }

Collections.sort方法底层调用的Arrays.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 为null,进入sort(a)方法。如下:

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

legacyMergeSort(a),归并排序,

ComparableTimSort.sort():即Timsort排序。

Arrays.sort底层实现

除了以上Collections.sort 中 调用的arrays.sort方法,还有
Arrays.sort()针对基本类型数组和对象数组采用不同的排序方法:

基本类型数组采用DualPivotQuicksort.sort(),快速排序的一种优化:双枢轴快速排序。

public static void sort(int[] a) {
        DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
    }

对象数组采用legacyMergeSort() 归并排序和 ComparableTimSort.sort() TimSort 排序。

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

    /** To be removed in a future release. */
    private static void legacyMergeSort(Object[] a) {
        Object[] aux = a.clone();
        mergeSort(aux, a, 0, a.length, 0);
    }

LegacyMergeSort.userRequested这个bool值是什么呢?
跟踪这个值,我们发现有这样的一段定义:

Old merge sort implementation can be selected (for
compatibility with broken comparators) using a system property.
Cannot be a static boolean in the enclosing class due to
circular dependencies. To be removed in a future release.

一种老的归并排序,现在默认是关的。

对对象进行排序,没有采用快速排序,原因:快速排序不稳定,TimSort是稳定的。
对于基本类型,由于不要求排序是稳定的,因此使用了平均效率最好的排序算法——快速排序

扩展

java.util.Arrays类中的一些列重载的sort的方法为给定数组进行排序,以下是各个重载方法:

在这里插入图片描述

综上:对于Arrays类中的sort方法,根据第一个参数的类型,可以将这些方法分为3类:

  1. 基本数据类型数组的数值排序方法:提供了对于byte,short,int,long,char,float,double这些基本数据类型的数组的排序方法;
  2. 自定义类的对象数组排序方法:提供了对于任意类类型个数组的排序方法,这些方法的输入参数为Object数组;
  3. 泛型方法提供了泛型对象数组的排序实现。

jdk 5

基本类型排序:优化的快速排序 ;
对象数组的排序:经过修改的归并排序

jdk1.7

DualPivotQuickSort 是jdk 1.7 开始采用的双枢轴快速排序,这种快速排序算法,相对于传统的单Pivot的快速排序效率要更好.

TimSort 是 jdk 1.7 开始采用的,它是一种二分插入排序和归并排序的变种算法

过程

两个阀值
286,47.
宏观
数据规模<47 使用插入排序,47<=数据规模<286 用双枢轴快速排序,数据规模>=286 用TimSort 排序
细节
先判断数据规模是否 < 286,
否:TimSort排序:判断数组是否具备结构(按升序或降序寻找run, run个数>67, 无结构,用双枢轴快排,<67 有结构,合并run栈(归并排序))
是:再判断数据规模是否<47, 是: 插入排序 否: 双枢轴快速排序

https://www.imooc.com/article/45462

https://my.oschina.net/hosee/blog/652280

双枢轴快速排序原理

双基准快排(DualPivotQuicksort),顾名思义有两个轴元素pivot1,pivot2,且pivot≤pivot2,将序列分成三段:x < pivot1、pivot1 ≤ x ≤ pivot2、x>pivot2,然后分别对三段进行递归,这个算法通常会比传统的快排效率更高

https://mp.weixin.qq.com/s/Jl0KdeFp2gStD_qdc3MYrA

归并排序原理

TimSort 原理

找到数据中已经排好序的块-分区,每一个分区叫一个run,然后按规则合并这些run。

Timsort的核心过程

   TimSort 算法为了减少对升序部分的回溯和对降序部分的性能倒退,将输入按其升序和降序特点进行了分区。排序的输入的单位不是一个个单独的数字,而是一个个的块-分区。其中每一个分区叫一个run。针对这些 run 序列,每次拿一个 run 出来按规则进行合并。每次合并会将两个 run合并成一个 run。合并的结果保存到栈中。合并直到消耗掉所有的 run,这时将栈上剩余的 run合并到只剩一个 run 为止。这时这个仅剩的 run 便是排好序的结果。

综上述过程,Timsort算法的过程包括

(0)如何数组长度小于某个值,直接用二分插入排序算法

(1)找到各个run,并入栈

(2)按规则合并run

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

一个处女座的程序媛

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

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

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

打赏作者

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

抵扣说明:

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

余额充值