Arrays.sort(arr)是什么排序及代码逻辑

 更新时间:2022年2月2日 18:27  点击:254 作者:可乐加品客

在学习过程中观察到Arrays.sort(arr)算法可以直接进行排序,但不清楚底层的代码逻辑是什么样子,记得自己之前在面试题里面也有面试官问这个问题,只能说研究之后发现还是比较复杂的,并不是网上说的快排或者二分插入之类的。

首先看源码:

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

它调用了DualPivotQuicksort的sort方法,乍一看以为是快排,这是很多网上的博主的说法,继续点开向下看(代码太长,没耐心看可以直接跳过该段代码QWQ):

 static void sort(int[] a, int left, int right,
                     int[] work, int workBase, int workLen) {
        // Use Quicksort on small arrays
        if (right - left < QUICKSORT_THRESHOLD) {
            sort(a, left, right, true);
            return;
        }
        /*
         * Index run[i] is the start of i-th run
         * (ascending or descending sequence).
         */
        int[] run = new int[MAX_RUN_COUNT + 1];
        int count = 0; run[0] = left;
        // 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;
            }
        }
        // Check special cases
        // Implementation note: variable "right" is increased by 1.
        if (run[count] == right++) { // The last run contains one element
            run[++count] = right;
        } else if (count == 1) { // The array is already sorted
            return;
        }
        // Determine alternation base for merge
        byte odd = 0;
        for (int n = 1; (n <<= 1) < count; odd ^= 1);
        // Use or create temporary array b for merging
        int[] b;                 // temp array; alternates with a
        int ao, bo;              // array offsets from 'left'
        int blen = right - left; // space needed for b
        if (work == null || workLen < blen || workBase + blen > work.length) {
            work = new int[blen];
            workBase = 0;
        }
        if (odd == 0) {
            System.arraycopy(a, left, work, workBase, blen);
            b = a;
            bo = 0;
            a = work;
            ao = workBase - left;
        } else {
            b = work;
            ao = 0;
            bo = workBase - left;
        }
        // Merging
        for (int last; count > 1; count = last) {
            for (int k = (last = 0) + 2; k <= count; k += 2) {
                int hi = run[k], mi = run[k - 1];
                for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) {
                    if (q >= hi || p < mi && a[p + ao] <= a[q + ao]) {
                        b[i + bo] = a[p++ + ao];
                    } else {
                        b[i + bo] = a[q++ + ao];
                    }
                }
                run[++last] = hi;
            }
            if ((count & 1) != 0) {
                for (int i = right, lo = run[count - 1]; --i >= lo;
                    b[i + bo] = a[i + ao]
                );
                run[++last] = right;
            }
            int[] t = a; a = b; b = t;
            int o = ao; ao = bo; bo = o;
        }
    }

代码很长,简要翻译过来,这里分了好几种情况:

1.数组长度小于286

这里又会调用一个sort方法,点开该sort(),又会划分情况:

数组长度小于47,

当leftmost(导入的一个布尔参数)为true,则使用直接插入排序;

否则会调用另一种插入办法,这里可以观察到一个注释:

/*
  * Every element from adjoining part plays the role
  * of sentinel, therefore this allows us to avoid the
  * left range check on each iteration. Moreover, we use
  * the more optimized algorithm, so called pair insertion
  * sort, which is faster (in the context of Quicksort)
  * than traditional implementation of insertion sort.
  */

大致意思是:相邻部分的每个元素都扮演着哨兵的角色,因此这允许我们避免在每次迭代中进行左范围检查。此外,我们使用了更优化的算法,即所谓的成对插入排序,它比插入排序的传统实现更快(在快速排序的上下文中)。

不过注意到,原函数参数传参在这里leftmost为true,所以一定是直接插入排序,以上作为了解。

数组长度大于47,采用一种快速排序的办法,这里因为代码太长,学艺不精,参考了一下https://www.jb51.net/article/236440.htm:

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

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

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

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

当数组长度大于286时

此时回到那段很长很长的代码段,在判断小于286的长度数组之后,从注解中:

// Check if the array is nearly sorted

这里是指检查数组元素是不是快要排列好了,或者书面一点说,是不是有一定结构了,然后看后面的for循环,注意到一段代码:

 if (++count == MAX_RUN_COUNT) {
                sort(a, left, right, true);
                return;
            }

这里的sort和我们上面在数组长度小于286时的那个sort方法是同一个方法,而针对这个count,是用来记录逆序组的,打个比方:

此时有一个数组为1 5 6 9 8 7 2 3

当数组认定我们的顺序应该为升序时,从第一个数开始数,此时9 8 7 2为降序,这就是逆序,将这四个数组合成一个组称为逆序组,然后再从3开始往后看。

当统计到一个逆序组时,count++,所以可以看出,count是用来记逆序组的,那么逆序组越多,这个结构就越混乱

MAX_RUN_COUNT == 67 ,因此当count一直加到67时,就说明已经在一个混乱的临界值了,此时执行sort()方法

通过这一段分析,我们理一下思路:

​如果数组能运行到这里,说明数组的长度大于等于286。符合该条件时,我们要判断这个数组是否有一定的结构:

(1)count<67,说明不是那么混乱,有一定结构,跳过;

(2)count>=67,说明已经混乱了,没有结构,执行sort方法,而已知数组长度大于等于286,那么必然大于47,一定执行快速排序。

跳过之后,经过代码的一大堆前置操作,最后看见下面的代码里面一行注释:

//Merging

显然,这里后面用到归并排序了,不详细赘述。

好了,最后总结:

  • 数组长度小于286时,根据数组长度,分两种情况:
    • 数组长度小于47,使用直接插入排序
    • 数组长度大于47,使用快速排序
  • 数组长度大于286时,根据数组排序情况,分两种情况:
    • 数组内顺序较为混乱,即count逆序组数大于等于67,使用快速排序
    • 数组内有一定顺序,即count逆序组数小于67,使用归并排序

参考资料:

《Java的Arrays.sort()方法到底用的什么排序算法》https://www.cnblogs.com/baichunyu/p/11935995.html作者:白春雨

到此这篇关于Arrays.sort(arr)是什么排序的文章就介绍到这了,更多相关Arrays.sort(arr)排序内容请搜索猪先飞以前的文章或继续浏览下面的相关文章希望大家以后多多支持猪先飞!

原文出处:https://www.cnblogs.com/cola-pink/archive/2022/01/29/1585609

[!--infotagslink--]

相关文章

  • antdesign-vue结合sortablejs实现两个table相互拖拽排序功能

    这篇文章主要介绍了antdesign-vue结合sortablejs实现两个table相互拖拽排序功能,本文通过实例图文相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-01-09
  • C# 参数按照ASCII码从小到大排序(字典序)

    这篇文章主要介绍了C# 参数按照ASCII码从小到大排序(字典序)的方法,非常不错,具有参考借鉴价值,需要的朋友可以参考下...2020-06-25
  • js实现列表按字母排序

    这篇文章主要为大家详细介绍了js实现列表按字母排序,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-08-11
  • C#实现排序的代码详解

    在本篇文章里小编给大家整理的是关于C#实现排序的代码以及相关知识点,需要的朋友们参考下。...2020-06-25
  • js实现数组冒泡排序、快速排序原理

    这篇文章主要为大家详细介绍了js实现数组冒泡排序、快速排序的原理,感兴趣的小伙伴们可以参考一下...2016-03-10
  • 图文详解Heap Sort堆排序算法及JavaScript的代码实现

    这篇文章以图文详解Heap Sort堆排序算法及JavaScript的代码实现,堆排序算法基于类二叉树的堆数据结构,需要的朋友可以参考下...2016-05-05
  • c# n个数排序实现代码

    c# n个数排序实现代...2020-06-25
  • 分享javascript实现的冒泡排序代码并优化

    本文给大家汇总介绍了几个个人收藏的JavaScript实现冒泡排序的代码,都是非常的不错,有需要的小伙伴可以参考下...2016-06-12
  • C#使用linq对数组进行筛选排序的方法

    这篇文章主要介绍了C#使用linq对数组进行筛选排序的方法,实例分析了C#实用linq扩展进行数组排序的技巧,具有一定参考借鉴价值,需要的朋友可以参考下...2020-06-25
  • JS实现的随机排序功能算法示例

    这篇文章主要介绍了JS实现的随机排序功能算法,结合具体实例形式分析了javascript常用的排序算法实现技巧,需要的朋友可以参考下...2017-06-15
  • C#实现冒泡排序算法的代码示例

    冒泡排序即是对数组每次轮循出最大数或最小数放在队尾,这里我们来看一下C#实现冒泡排序算法的代码示例,需要的朋友可以参考下...2020-06-25
  • jQuery实现对无序列表的排序功能(附demo源码下载)

    这篇文章主要介绍了jQuery实现对无序列表的排序功能,涉及jQuery与javascript常见的文本操作函数与sort排序函数的相关使用方法,具有一定参考借鉴价值,需要的朋友可以参考下...2016-07-01
  • C++ 字符串去重排序实例代码

    这篇文章主要介绍了C++ 字符串去重排序实例代码的相关资料,需要的朋友可以参考下...2020-04-25
  • 利用JavaScript对中文(汉字)进行排序实例详解

    排序是我们在日常开发中经常遇到的一个功能,下面这篇文章主要给大家介绍了利用JavaScript对中文(汉字)进行排序的相关资料,文中通过示例代码介绍的非常详细,对大家具有一定的参考学习价值,需要的朋友们下面跟着小编一起来看看吧。...2017-06-24
  • JavaScript数值数组排序示例分享

    但是,我们在使用中就会发现问题,这里的数组排序方法并不是按照我们想像中的数字大小来排序的,而是按照字符串测试结果改变原先的数据。这并不是我们想要的。那么如何才可以得到我们想要的按照我们思维中的数字大小来排序...2014-05-31
  • C++ STL关联式容器自定义排序规则的2种方法

    这篇文章主要介绍了C++ STL关联式容器自定义排序规则的2种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-03-04
  • C语言开发之归并排序详解及实例

    这篇文章主要介绍了 C语言开发之归并排序详解及实例的相关资料,需要的朋友可以参考下...2020-04-25
  • VC++实现选择排序算法简单示例

    这篇文章主要介绍了VC++实现选择排序算法简单示例,代码简洁易懂,有助于读者对数据结构与算法的学习,需要的朋友可以参考下...2020-04-25
  • oracle实现按天,周,月,季度,年查询排序方法

    这篇文章主要介绍了oracle按天,周,月,季度,年查询排序功能,本文给出了sql语句,每种方法给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下...2020-07-11
  • vue实现页面div盒子拖拽排序功能

    本文主要介绍了vue实现页面div盒子拖拽排序功能,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-10-22