java Arrays.sort源码学习之旅(一)

Arrays.sort源码学习之旅(一)

     你们在使用Arrays.sort()函数的时候,有没有好奇过它的实现方法,是不是有想过它是用冒泡排序来实现的(我刚开始就是这么觉得的,等自己仔细看了源码之后,才发现自己好天真)。
     这里仅对没有自带比较器的array进行分析,在源码中,对不同的数据类型采用排序方式是不同的,总体分为以下四类。
  1. byte
  2. int 和 long
  3. char 和 short
  4. float 和 double
byte
(1)length > 29时,巧妙的采用计数排序。因为byte的大小是在固定范围的(-128~127),且有固定排序,所以只需将各个byte的数量存储到一个大小为256的计数数组count[256]中,而数组相应的下标就是byte_value + 128,然后再将相应个数的index值-128写入排序数据即可。
(2)length <= 29时,采用插入排序,这个不多说了,大家都懂。


int 和long:
(1)length < 286时,采用Dual-Pivot Quicksort(后面说明原理)我形象的称其为双端快排。 
(2)length >= 286时,先检查array,若是已经排好序的,直接返回;若是接近排好序的,采用归并排序;其他采用Dual-Pivot Quicksort排序。什么是接近排好序的呢?类似于123234978,其可以分为三个已经排好序的序列123 | 2349 | 78。

Dual-Pivot Quicksort原理:
(1)length < 47 时,采用插入排序:分两种,一种是传统的插入排序,另一种是先检查从array开始端是否有已经排好序的序列,找到其末端index,对index之后的元素使用插入排序。
(2)length >= 47时,选取两个基准点(pivot1 <= pivot2,当pivot1 = pivot2时,看成一个基准点);找到array中小于pivot1的部分放到左边(也即小端部分),找到array中大于pivot2的部分放到右边(也即大端部分);再对小端和大端使用双端快排(这时,迭代开始,回到(1)判断,直到排好序);最后对pivot1和pivot2之间的部分采用双端快排(再次迭代回到(1)判断,直到排好序)。

下面采用图像来描述双端快排:

其中e1~e5是数组下标,其中array[e1] < array[e2] < array[e3] < array[e4] < array[e5],pivot1 = array[e2],pivot2 = array[e4],若
array[e1] = array[e2] = array[e3] = array[e4] = array[e5] 中的任何一个等号成立,pivot1和pivot2同时指向到array[e3]。



一次双端快排后:


左端聚集的元素都 < pivot1,右端聚集的元素都 > pivot2,less表示小端末尾,great表示大端开头。

char 和 short:
(1)length > 3200 时,采用计数排序,原理和byte相似,只不过数组长度变为了65536.
(2)length <= 3200时,采用和 int 相同的排序方式。

float 和 double:
(1)先进行NaN数判断,将NaN数放到array末尾;
(2)对非NaN部分进行同 int 相同的排序方式;
(3)插入NaN数。对于NaN数,在我的理解是无穷数(也即正/负无穷小)。对于插入NaN数,是将负无穷小放在负数和零之间,将正无穷小放在零和正数之间。

哈哈,总算写完了,本人java新人一枚,第一次写博客(手有点抖),有错的地方,随便喷,正好可以解解大伙常常加班带来的闷气。 对于自带比较器的array排序,下一次再来了。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值