Java的Arrays.sort()方法到底用的什么排序算法
暂时网上看过很多JDK8中Arrays.sort的底层原理,有些说是插入排序,有些说是归并排序,也有说大于域值用计数排序法,否则就使用插入排序。。。其实不全对。让我们分析个究竟:
1 // Use Quicksort on small arrays
2 if (right - left < QUICKSORT_THRESHOLD)
3 {
4 //QUICKSORT_THRESHOLD = 286
5 sort(a, left, right, true);
6 return;
7 }
数组一进来,会碰到第一个阀值QUICKSORT_THRESHOLD(286),注解上说,小过这个阀值的进入Quicksort (快速排序),其实并不全是,点进去sort(a, left, right, true);方法:
1 // Use insertion sort on tiny arrays
2 if (length < INSERTION_SORT_THRESHOLD)
3 {
4 if (leftmost)
5 {
6 ......
点进去后我们看到第二个阀值INSERTION_SORT_THRESHOLD(47),如果元素少于47这个阀值,就用插入排序,往下看确实如此:
1 /*
2 * Traditional (without sentinel) insertion sort,
3 * optimized for server VM, is used in case of
4 * the leftmost part.
5 */
6 for (int i = left, j = i; i < right; j = ++i)
7 {
8 int ai = a[i + 1];
9 while (ai < a[j])
10 {
11 a[j + 1] = a[j];
12 if (j-- == left)
13 {
14 break;
15 }
16 }
17 a[j + 1] = ai;

元素少于47用插入排序
至于大过INSERTION_SORT_THRESHOLD(47)的,用一种快速排序的方法:
1.从数列中挑出五个元素,称为 “基准”(pivot);
2.重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
3.递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
快速排序(Quick Sort)
这是少于阀值QUICKSORT_THRESHOLD(286)的两种情况,至于大于286的,它会进入归并排序(Merge Sort),但在此之前,它有个小动作:
1 // Check if the array is nearly sorted
2 for (int k = left; k < right; run[count] = k) { if (a[k] < a[k + 1]) { // ascending
3 while (++k <= right && a[k - 1] <= a[k]);
4 } else if (a[k] > a[k + 1]) { // descending
5 while (++k <= right && a[k - 1] >= a[k]); for (int lo = run[count] - 1, hi = k; ++lo < --hi; ) { int t = a[lo]; a[lo] = a[hi]; a[hi] = t;
6 }
7 } else { // equal
8 for (int m = MAX_RUN_LENGTH; ++k <= right && a[k - 1] == a[k]; ) { if (--m == 0) {
9 sort(a, left, right, true); return;
10 }
11 }
12 } /*
13 * The array is not highly structured,
14 * use Quicksort instead of merge sort.
15 */
16 if (++count == MAX_RUN_COUNT) {
17 sort(a, left, right, true); return;
18 }
19 }
这里主要作用是看他数组具不具备结构:实际逻辑是分组排序,每降序为一个组,像1,9,8,7,6,8。9到6是降序,为一个组,然后把降序的一组排成升序:1,6,7,8,9,8。然后最后的8后面继续往后面找。
每遇到这样一个降序组,++count,当count大于MAX_RUN_COUNT(67),被判断为这个数组不具备结构(也就是这数据时而升时而降),然后送给之前的sort(里面的快速排序)的方法(The array is not highly structured,use Quicksort instead of merge sort.)
如果count少于MAX_RUN_COUNT(67)的,说明这个数组还有点结构,就继续往下走下面的归并排序。
总结:
从上面分析,Arrays.sort并不是单一的排序,而是插入排序,快速排序,归并排序三种排序的组合,为此我画了个流程图:

O(nlogn)只代表增长量级,同一个量级前面的常数也可以不一样,不同数量下面的实际运算时间也可以不一样。
数量非常小的情况下(就像上面说到的,少于47的),插入排序等可能会比快速排序更快。 所以数组少于47的会进入插入排序。
快排数据越无序越快(加入随机化后基本不会退化),平均常数最小,不需要额外空间,不稳定排序。
归排速度稳定,常数比快排略大,需要额外空间,稳定排序。
所以大于或等于47或少于286会进入快排,而在大于或等于286后,会有个小动作:“// Check if the array is nearly sorted”。这里第一个作用是先梳理一下数据方便后续的归并排序,第二个作用就是即便大于286,但在降序组太多的时候(被判断为没有结构的数据,The array is not highly structured,use Quicksort instead of merge sort.),要转回快速排序。
Java的Arrays.sort()方法到底用的什么排序算法的更多相关文章
- 关于Java中Arrays.sort()方法TLE
最近一直在练用Java写题,今天无意发现一道很简单的二分题(链接),我一开始是直接开int[]数组调用Arrays.sort()去排序,没想到TLE了,原来是因为jdk中对于int[]的排序是使用快速 ...
- java中Arrays.sort()对二位数组进行排序
int [][]a = new int [5][2]; //定义一个二维数组,其中所包含的一维数组具有两个元素 对于一个已定义的二位数组a经行如下规则排序,首先按照每一个对应的一维数组第一个元素进行升 ...
- Java 使用Arrays.sort排序 从大到小排列
前言 一般情况,我们在Java中给数组排序,比起自己写个冒泡排序,更加喜欢使用Java中自带的sort方法,也就是Arrays.sort方法 但是,这个方法只会将数组从小到大排列,如果我们需要从大到小 ...
- js 排序:sort()方法、冒泡排序、二分法排序。
js中的排序,这里介绍三种,sort()方法.冒泡排序.二分法排序. 1.sort方法 写法: 数组.sort(); 返回排好序的数组,如果数组里是数字,则由小到大,如果是字符串,就按照第一个字符的 ...
- java.util.Arrays.sort两种方式的排序(及文件读写练习)
import java.io.*; import java.util.*; public class SortTest{ public static void main(String args[]) ...
- Java中Arrays.sort()和Collections.sort()
1.简单示例 sort方法的使用非常的简单明了,下面的例子中,先定义一个比较Dog大小的Comparator,然后将其实例对象作为参数传给sort方法,通过此示例,你应该能够快速掌握Arrays.so ...
- java.util. Arrays.sort(scores);
import java.util.*; public class ArraySortScore { //完成 main 方法 public static void main(String[] args ...
- 集合(一)-Java中Arrays.sort()自定义数组的升序和降序排序
默认升序 package peng; import java.util.Arrays; public class Testexample { public static void main(Stri ...
- Java的Collection.sort()方法
Java中的Collection.sort()方法能使用泛型对对象的变量进行排序,下面是两种方法. 文件名:student.java import java.util.*; import com.su ...
随机推荐
- 在C++中使用libuv时对回调的处理 (2)
前情简介 在完成了第一版的<在C++中使用libuv时对回调的处理>之后,在对项目进行开发的时候,还是感觉有一些难受. 因为在实际操作的时候,需要构建一个结构体,并且需要对这个结构体的内存 ...
- 引用类型之Array(二)
操作方法 concat( ) concat() 方法用于连接两个或多个数组. 该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本. 语法 arrayObject.concat(arrayX,a ...
- STM32F103C8T6-CubeMx串口收发程序详细设计与测试(1)——CubeMx生成初始代码
STM32F103C8T6-CubeMx串口收发程序详细设计与测试(1)--CubeMx生成初始代码 关键词:STM32F103C8T6 CubeMX UART 详细程序设计 1.开发环境 (1)ST ...
- 诊断日志知多少 | DiagnosticSource 在.NET上的应用
1. 引言 最近为了解决ABP集成CAP时无法通过拦截器启用工作单元的问题,从小伙伴那里学了一招.借助DiagnossticSource,可以最小改动完成需求.关于DiagnosticSource晓东 ...
- 笔记本键盘按U键却变成了4
解答 笔记本键盘U盘变成了4,是因为你开启了小键盘功能.出现该问题,只要关闭小键盘功能即可,操作如下: 按住键盘下方的Fn,同时按住键盘顶部的F键中标有Numlk的键. 电脑屏幕出现解锁标志,小键盘功 ...
- Java死锁编码及定位分析的demo
死锁 死锁是什么 大学课程中的四个要素: (1)互斥(2)不可抢占(3)循环等待(4)请求保持 也就是下图所描述 产生死锁的主要原因 (1)系统资源不足(2)进程运行推进的顺序不合适(3)资源分配不当 ...
- 2016年 实验四 B2B模拟实验
实验四 B2B模拟实验 [实验目的] ⑴.掌握B2B中供应商的供求信息发布.阿里商铺开设和订单交易等过程. ⑵.掌握B2B中采购商的采购信息的发布.交易洽谈.网上支付和收货等过程. [实验条件] ⑴ ...
- 使用Python对植物大战僵尸学习研究
根据上一篇 使用Python读写游戏1 中,使用Python win32库,对一款游戏进行了读内存 操作. 今天来写一下对内存进行写的操作 正文 要进行32位的读写,首先了解一下要用到的几个函数,通过 ...
- 2020年java全套教程,此套java涵盖了pdf,java源码,项目案例,完整视频约3000G的资源
疫情期间,百无聊赖,是不是需要充电一下,让自己更有竞争力呢?学习java一定要快呦! 废话不多说了,网盘已经爆炸了,把2006年-2020年的全部资料都发给爱学习的你吧, 希望可以改变你的命运,或者是 ...
- MeteoInfoLab脚本示例:AIRS Grid HDF数据
AIRS Grid HDF数据是HDF4 EOS格式,数据地理坐标信息可以被MeteoInfo自动识别,脚本程序更为简单.需要注意的是读取数据时Y轴是反向的(卫星数据通常如此).脚本程序: #Add ...