java8 sort_java8中List中sort方法解析

概述集合类中的sort方法,听说在java7中就引入了,但是我没有用过java7,不太清楚,java8中的排序是采用Timsort排序算法实现的,这个排序最开始是在python中由Tim Peters实现的,后来Java觉得不错,就引入了这个排序到Java中,竟然以作者的名字命名,搞得我还以为这个Tim是一个单词的意思,了不起,本文就从Arrays中实现的排序分析一下这个排序算法的原理,本文只会从...
摘要由CSDN通过智能技术生成

概述

集合类中的sort方法,听说在java7中就引入了,但是我没有用过java7,不太清楚,java8中的排序是采用Timsort排序算法实现的,这个排序最开始是在python中由Tim Peters实现的,后来Java觉得不错,就引入了这个排序到Java中,竟然以作者的名字命名,搞得我还以为这个Tim是一个单词的意思,了不起,本文就从Arrays中实现的排序分析一下这个排序算法的原理,本文只会从源码角度分析,不会从算法角度去分析。

进入List中查看sort方法源码如下:

default void sort(Comparator super E>c) {

Object[] a= this.toArray();// 这个方法很简单,就是调用Arrays中的sort方法进行排序Arrays.sort(a, (Comparator) c);

ListIterator i = this.listIterator();for(Object e : a) {

i.next();

i.set((E) e);

}

}

进入Arrays.sort()方法

public static void sort(T[] a, Comparator super T>c) {//这个是自己传入的比较器如果为空,这里的a为存放数据的数组,那数组中的的元素都必须实现Comparator接口 if (c == null) {

sort(a);

}else{

//这个判断没有细看,不太清楚在判断什么if(LegacyMergeSort.userRequested)

legacyMergeSort(a, c);else

//这里就是所谓的TimSort了 TimSort.sort(a, 0, a.length, c, null, 0, 0);

}

}

由于sort()和TimSort.sort走的流程基本一致,这里只分析TimSort.sort()方法,进入该方法。

这里有必要先说一下TimSort排序算法的核心内容,了解这个算法的核心内容有助于看下面的代码。

TimSort的核心是这样:

1.如果数组的长度小于32,直接采用二分法插入排序,就是下面方法中的binarySort方法实现的,这个算法原理,我举个例子大家就明白了

假设数组为:[1,3,9,6,2],二分法插入排序插入如下:

I:从开头先把自然升序(或降序)段找出来,那什么是自然升序段,就是没有经过排序算法,原始数据就是有序的,本数组中自然升序段就是1,3,9

II:按照正常的思维,直接拿6,从头开始和前三个元素一个一个比较也可以实现排序,但是这样效率太低,那怎么做可以效率高点呢?就是我们之前高数中学的二分查找法,就是通过二分查找法,我先找到3,发现6 > 3,那我就不用和1进行比较了。

2.如果数组的长度大于32,那就把数组拆分成一个一个的小段,每段的长度在16~32之间,使用上面介绍的二分法插入排序,把每一段进行排序,之后在把每一个排好序的段进行合并,最终就可以实现整个数组的排序,大致的思想就是这样,这个叙述可能会给大家一种误解,就是认为每一段都排好序之后在进行合并,其实不是这样的,而是每一段边排序,如果符合特定条件就会合并。

有了上面的了解,我们再来看下面的代码

static void sort(T[] a, int lo, int hi, Comparator super T>c,

T[] work,int workBase, intworkLen) {assert c != null && a != null && lo >= 0 && lo <= hi && hi <=a.length;

//这里是数组中剩余没有排序的元素个数,初始长度为数组的长度int nRemaining = hi -lo;if (nRemaining < 2)return; //Arrays of size 0 and 1 are always sorted//这里的MIN_MERGE就是32,如果数组长度小于32,直接采用二分法插入排序

//If array is small, do a "mini-TimSort" with no merges

if (nRemaining

binarySort(a, lo, hi, lo+initRunLen, c);return;

}/*** March over the array once, left to right, finding natural runs,

* extending short natural runs to minRun elements, and merging runs

* to maintain stack invariant.*/

//这个是TimSort核心类,很多处理逻辑都是这个里面 TimSort ts = new TimSort<>(a, c, work, workBase, workLen);//<1.1> 这个就是计算分割之后每一段的长度的 int minRun =minRunLength(nRemaining);do{//Identify next run//<1.2> 寻找自然增长的结束位置 int runLen =countRunAndMakeAscending(a, lo, hi, c);//If run is short, extend to min(minRun, nRemaining)

if (runLen 对每一段进行二分法插入排序 binarySort(a, lo, lo + force, lo +runLen, c);

runLen=force;

}//Push run onto pending-run stack, and maybe merge,将每一段的起始位置和每一段的分段长度放入栈中

ts.pushRun(lo, runLen);//<1.4> 合并排好序的段,这个就是上面我说的并不是等所有的都排好序了再合并ts.mergeCollapse();//Advance to find next run

lo +=runLen;

// 将已经排好序的段,从总长度中减去

nRemaining-=runLen;

}while (nRemaining != 0);//Merge all remaining runs to complete sort

assert lo ==hi;//<1.5> 最终排序,这个方法在整个排序中只会执行一次ts.mergeForceCollapse();assert ts.stackSize == 1;

}

上面注释中<1.1>, minRunLength(nRemaining)

private static int minRunLength(intn) {assert n >= 0;int r = 0;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值