广告位联系
返回顶部
分享到

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

java 来源:互联网 作者:秩名 发布时间:2022-02-02 21:06:14 人浏览
摘要

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

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

首先看源码:

1

2

3

public static void sort(int[] a) {

       DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);

   }

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

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循环,注意到一段代码:

1

2

3

4

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作者:白春雨


版权声明 : 本文内容来源于互联网或用户自行发布贡献,该文观点仅代表原作者本人。本站仅提供信息存储空间服务和不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权, 违法违规的内容, 请发送邮件至2530232025#qq.cn(#换@)举报,一经查实,本站将立刻删除。
原文链接 : https://www.cnblogs.com/cola-pink/archive/2022/01/29/15856097.html
相关文章
  • SpringBoot自定义错误处理逻辑介绍

    SpringBoot自定义错误处理逻辑介绍
    1. 自定义错误页面 将自定义错误页面放在 templates 的 error 文件夹下,SpringBoot 精确匹配错误信息,使用 4xx.html 或者 5xx.html 页面可以打印错误
  • Java实现手写一个线程池的代码

    Java实现手写一个线程池的代码
    线程池技术想必大家都不陌生把,相信在平时的工作中没有少用,而且这也是面试频率非常高的一个知识点,那么大家知道它的实现原理和
  • Java实现断点续传功能的代码

    Java实现断点续传功能的代码
    题目实现:网络资源的断点续传功能。 二、解题思路 获取要下载的资源网址 显示网络资源的大小 上次读取到的字节位置以及未读取的字节
  • 你可知HashMap为什么是线程不安全的
    HashMap 的线程不安全 HashMap 的线程不安全主要体现在下面两个方面 在 jdk 1.7 中,当并发执行扩容操作时会造成环形链和数据丢失的情况 在
  • ArrayList的动态扩容机制的介绍

    ArrayList的动态扩容机制的介绍
    对于 ArrayList 的动态扩容机制想必大家都听说过,之前的文章中也谈到过,不过由于时间久远,早已忘却。 所以利用这篇文章做做笔记,加
  • JVM基础之字节码的增强技术介绍

    JVM基础之字节码的增强技术介绍
    字节码增强技术 在上文中,着重介绍了字节码的结构,这为我们了解字节码增强技术的实现打下了基础。字节码增强技术就是一类对现有字
  • Java中的字节码增强技术

    Java中的字节码增强技术
    1.字节码增强技术 字节码增强技术就是一类对现有字节码进行修改或者动态生成全新字节码文件的技术。 参考地址 2.常见技术 技术分类 类
  • Redis BloomFilter布隆过滤器原理与实现

    Redis BloomFilter布隆过滤器原理与实现
    Bloom Filter 概念 布隆过滤器(英语:Bloom Filter)是1970年由一个叫布隆的小伙子提出的。它实际上是一个很长的二进制向量和一系列随机映射
  • Java C++算法题解leetcode801使序列递增的最小交换次

    Java C++算法题解leetcode801使序列递增的最小交换次
    题目要求 思路:状态机DP 实现一:状态机 Java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Solution { public int minSwap(int[] nums1, int[] nums2) { int n
  • Mybatis结果集映射与生命周期介绍

    Mybatis结果集映射与生命周期介绍
    一、ResultMap结果集映射 1、设计思想 对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了 2、resultMap的应用场
  • 本站所有内容来源于互联网或用户自行发布,本站仅提供信息存储空间服务,不拥有版权,不承担法律责任。如有侵犯您的权益,请您联系站长处理!
  • Copyright © 2017-2022 F11.CN All Rights Reserved. F11站长开发者网 版权所有 | 苏ICP备2022031554号-1 | 51LA统计