Java的Arrays.sort()方法排序算法实例分析

 更新时间:2022年02月02日 09:54:27   作者:白春雨  
网上看过很多JDK8中Arrays.sort的底层原理,有些说是插入排序,有些说是归并排序,也有说大于域值用计数排序法,否则就使用插入排序,这种说法到底对吗?下面通过本文给大家分析下Java的Arrays.sort()方法到底用的什么排序算法,感兴趣的朋友一起看看吧

  暂时网上看过很多JDK8中Arrays.sort的底层原理,有些说是插入排序,有些说是归并排序,也有说大于域值用计数排序法,否则就使用插入排序。。。其实不全对。让我们分析个究竟:

// Use Quicksort on small arrays
if (right - left < QUICKSORT_THRESHOLD)
{
       //QUICKSORT_THRESHOLD = 286
        sort(a, left, right, true);
        return;
 }

  数组一进来,会碰到第一个阀值QUICKSORT_THRESHOLD(286),注解上说,小过这个阀值的进入Quicksort (快速排序),其实并不全是,点进去sort(a, left, right, true);方法:

// Use insertion sort on tiny arrays
if (length < INSERTION_SORT_THRESHOLD)
{
    if (leftmost)
    {
        ......

  点进去后我们看到第二个阀值INSERTION_SORT_THRESHOLD(47),如果元素少于47这个阀值,就用插入排序,往下看确实如此:

/*
 * Traditional (without sentinel) insertion sort,
 * optimized for server VM, is used in case of
 * the leftmost part.
 */
for (int i = left, j = i; i < right; j = ++i)
{
     int ai = a[i + 1];
     while (ai < a[j])
     {
          a[j + 1] = a[j];
          if (j-- == left)
          {
               break;
           }
      }
      a[j + 1] = ai;

元素少于47用插入排序

  至于大过INSERTION_SORT_THRESHOLD(47)的,用一种快速排序的方法:

  1.从数列中挑出五个元素,称为 “基准”(pivot);

  2.重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;

  3.递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。

快速排序(Quick Sort)

  这是少于阀值QUICKSORT_THRESHOLD(286)的两种情况,至于大于286的,它会进入归并排序(Merge Sort),但在此之前,它有个小动作:

// Check if the array is nearly sorted
    for (int k = left; k < right; run[count] = k) {        if (a[k] < a[k + 1]) { // ascending
            while (++k <= right && a[k - 1] <= a[k]);
        } else if (a[k] > a[k + 1]) { // descending
            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;
            }
        } else { // equal
            for (int m = MAX_RUN_LENGTH; ++k <= right && a[k - 1] == a[k]; ) {                if (--m == 0) {
                    sort(a, left, right, true);                    return;
                }
            }
        }        /*
         * The array is not highly structured,
         * use Quicksort instead of merge sort.
         */
        if (++count == MAX_RUN_COUNT) {
            sort(a, left, right, true);            return;
        }
    }

  这里主要作用是看他数组具不具备结构:实际逻辑是分组排序,每降序为一个组,像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()方法内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java class文件格式之属性详解_动力节点java学院整理

    Java class文件格式之属性详解_动力节点java学院整理

    这篇文章主要介绍了Java class文件格式之属性详解,需要的朋友可以参考下
    2017-06-06
  • 深入解析Java的包(package)

    深入解析Java的包(package)

    这篇文章主要介绍了深入解析Java的包(package),是Java入门学习中的基础知识,需要的朋友可以参考下
    2015-09-09
  • SpringCloud之监控数据聚合Turbine的实现

    SpringCloud之监控数据聚合Turbine的实现

    这篇文章主要介绍了SpringCloud之监控数据聚合Turbine的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-08-08
  • IDEA创建父项目和子项目的实现步骤

    IDEA创建父项目和子项目的实现步骤

    本文主要介绍了IDEA创建父项目和子项目的实现步骤,文中通过图文介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-07-07
  • Java中常用时间的一些相关方法

    Java中常用时间的一些相关方法

    日期的使用多种多样,但万变不离其宗,下面这篇文章主要给大家介绍了关于Java中常用时间的一些相关方法,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
    2021-10-10
  • Java中的构造方法和方法重载完整代码

    Java中的构造方法和方法重载完整代码

    在Java编程中,构造方法用于初始化对象,而方法重载允许同一个类中存在多个同名方法但参数不同,文中通过代码及图文介绍的非常详细,需要的朋友可以参考下
    2024-10-10
  • controller函数中参数列表使用多个@RequestBody问题

    controller函数中参数列表使用多个@RequestBody问题

    这篇文章主要介绍了controller函数中参数列表使用多个@RequestBody问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-04-04
  • Java构造方法 super 及自定义异常throw合集详解用法

    Java构造方法 super 及自定义异常throw合集详解用法

    异常是程序中的一些错误,但不是所有错误都是异常,且错误有时候是可以避免的,super可以理解为是指向自己超(父)类对象的一个指针,而这个超类指的是离自己最近的一个父类,构造器也叫构造方法、构造函数,是一种特殊类型的方法,负责类中成员变量(域)的初始化
    2021-10-10
  • 基于html5+java实现大文件上传实例代码

    基于html5+java实现大文件上传实例代码

    本文通过一段实例代码给大家介绍基于html5+java实现大文件上传,涉及到html5 java 文件上传相关知识,感兴趣的朋友一起学习吧
    2016-01-01
  • SrpingDruid数据源加密数据库密码的示例代码

    SrpingDruid数据源加密数据库密码的示例代码

    本篇文章主要介绍了SrpingDruid数据源加密数据库密码的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-10-10

最新评论