深入理解java中Arrays.sort()的用法

作者:github_38838414 时间:2021-05-26 22:25:58 

Java的Arrays类中有一个sort()方法,该方法是Arrays类的静态方法,在需要对数组进行排序时,非常的好用。

但是sort()的参数有好几种,基本上是大同小异,下面是以int型数组为例的Arrays.sort()的典型用法


import java.util.Arrays;
import java.util.Comparator;

/**
* Arrays.sort()排序
*/
public class SortTest
{
 public static void main(String []args)
 {
   int[] ints=new int[]{2,324,4,57,1};

System.out.println("增序排序后顺序");
   Arrays.sort(ints);
   for (int i=0;i<ints.length;i++)
   {
     System.out.print(ints[i]+" ");
   }

System.out.println("\n减序排序后顺序");
   //要实现减序排序,得通过包装类型数组,基本类型数组是不行滴
   Integer[] integers=new Integer[]{2,324,4,4,6,1};
   Arrays.sort(integers, new Comparator<Integer>()
   {
     /*
     * 此处与c++的比较函数构成不一致
     * c++返回bool型,而Java返回的为int型
     * 当返回值>0时
     * 进行交换,即排序(源码实现为两枢轴快速排序)
      */
     public int compare(Integer o1, Integer o2)
     {
       return o2-o1;
     }

public boolean equals(Object obj)
     {
       return false;
     }
   });
   for (Integer integer:integers)
   {
     System.out.print(integer+" ");
   }

System.out.println("\n对部分排序后顺序");
   int[] ints2=new int[]{212,43,2,324,4,4,57,1};
   //对数组的[2,6)位进行排序

Arrays.sort(ints2,2,6);
   for (int i=0;i<ints2.length;i++)
   {
     System.out.print(ints2[i]+" ");
   }

}
}

排序结果如下

增序排序后顺序
1 2 4 57 324
减序排序后顺序
324 6 4 4 2 1
对部分排序后顺序
212 43 2 4 4 324 57 1

打开Arrays.sort()源码,还是以int型为例,其他类型也是大同小异


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

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

从源码中发现,两种参数类型的sort方法都调用了 DualPivotQuicksort.sort()方法
继续跟踪源码


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;
   }
 }

结合文档以及源代码,我们发现,jdk中的Arrays.sort()的实现是通过所谓的双轴快排的算法


/**
* This class implements the Dual-Pivot Quicksort algorithm by
* Vladimir Yaroslavskiy, Jon Bentley, and Josh Bloch. The algorithm
* offers O(n log(n)) performance on many data sets that cause other
* quicksorts to degrade to quadratic performance, and is typically
* faster than traditional (one-pivot) Quicksort implementations.
*
* All exposed methods are package-private, designed to be invoked
* from public methods (in class Arrays) after performing any
* necessary array bounds checks and expanding parameters into the
* required forms.
*
* @author Vladimir Yaroslavskiy
* @author Jon Bentley
* @author Josh Bloch
*
* @version 2011.02.11 m765.827.12i:5\7pm
* @since 1.7
*/

Java1.8的快排是一种双轴快排,顾名思义:双轴快排是基于两个轴来进行比较,跟普通的选择一个点来作为轴点的快排是有很大的区别的,双轴排序利用了区间相邻的特性,对原本的快排进行了效率上的提高,很大程度上是利用了数学的一些特性。。。。。嗯。。。反正很高深的样子

算法步骤

1.对于很小的数组(长度小于27),会使用插入排序。
2.选择两个点P1,P2作为轴心,比如我们可以使用第一个元素和最后一个元素。
3.P1必须比P2要小,否则将这两个元素交换,现在将整个数组分为四部分:
(1)第一部分:比P1小的元素。
(2)第二部分:比P1大但是比P2小的元素。
(3)第三部分:比P2大的元素。
(4)第四部分:尚未比较的部分。
在开始比较前,除了轴点,其余元素几乎都在第四部分,直到比较完之后第四部分没有元素。
4.从第四部分选出一个元素a[K],与两个轴心比较,然后放到第一二三部分中的一个。
5.移动L,K,G指向。
6.重复 4 5 步,直到第四部分没有元素。
7.将P1与第一部分的最后一个元素交换。将P2与第三部分的第一个元素交换。
8.递归的将第一二三部分排序。

疑问:为啥不用泛型

来源:https://blog.csdn.net/github_38838414/article/details/80642329

标签:java,Arrays.sort()
0
投稿

猜你喜欢

  • Spring refresh()源码解析

    2022-09-04 18:45:52
  • JavaWeb项目Servlet无法访问问题解决

    2022-10-10 03:33:52
  • 用C#实现启动另一程序的方法实例

    2023-06-20 12:05:43
  • 谈谈Java中整数类型(short int long)的存储方式

    2023-01-01 08:24:33
  • 100行C#代码实现经典扫雷游戏

    2023-12-05 16:33:30
  • Java实现文件切割拼接的实现代码

    2022-04-15 08:10:03
  • Java解码H264格式视频流中的图片

    2023-11-24 23:58:24
  • 详解SpringCloud服务认证(JWT)

    2023-11-14 11:19:43
  • java并发编程之ThreadLocal详解

    2023-03-15 11:44:33
  • C#检查字符串是否是合法URL地址的方法

    2022-08-09 16:24:06
  • 详解Java中Callable和Future的区别

    2023-07-25 21:18:58
  • C#串口通信模块使用方法示例

    2023-06-19 12:13:57
  • Maven学习----Maven安装与环境变量配置教程

    2021-12-04 08:20:25
  • Spring声明式事务和@Aspect的拦截顺序问题的解决

    2023-07-18 12:10:46
  • 使用SpringBoot打jar包并部署到Tomcat详细步骤

    2023-12-06 07:15:16
  • java 字段值为null,不返回该字段的问题

    2023-07-13 10:32:34
  • Spring探秘之如何妙用BeanPostProcessor

    2021-07-01 22:41:46
  • 解析spring加载bean流程的方法

    2023-11-29 13:50:32
  • 流读取导致StringBuilder.toString()乱码的问题及解决

    2022-12-20 13:34:14
  • spring注解之@Valid和@Validated的区分总结

    2023-11-01 07:51:42
  • asp之家 软件编程 m.aspxhome.com