全国咨询/投诉热线:400-618-4000

java培训:深入理解Java 中的Arrays.sort()方法

更新时间:2019年04月17日15时08分 来源:java培训机构传智播客 浏览次数:

  深入理解Java 中的Arrays.sort()方法

  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

  {

  System.out.print(ints[i]+" ");

  }

  System.out.println("\n减序排序后顺序");

  //要实现减序排序,得通过包装类型数组,基本类型数组是不行滴

  Integer[] integers=new Integer[]{2,324,4,4,6,1};

  Arrays.sort(integers, new Comparator()

  {

  /*

  * 此处与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

  {

  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.递归的将第一二三部分排序。


推荐阅读:

Java视频教程

javaee

python

web

ui

cloud

test

c

netmarket

pm

Linux

movies

robot

uids

北京校区

    14天免费试学

    基础班入门课程限时免费

    申请试学名额

    15天免费试学

    基础班入门课程限时免费

    申请试学名额

    15天免费试学

    基础班入门课程限时免费

    申请试学名额

    15天免费试学

    基础班入门课程限时免费

    申请试学名额

    20天免费试学

    基础班入门课程限时免费

    申请试学名额

    8天免费试学

    基础班入门课程限时免费

    申请试学名额

    20天免费试学

    基础班入门课程限时免费

    申请试学名额

    5天免费试学

    基础班入门课程限时免费

    申请试学名额

    0天免费试学

    基础班入门课程限时免费

    申请试学名额

    12天免费试学

    基础班入门课程限时免费

    申请试学名额

    5天免费试学

    基础班入门课程限时免费

    申请试学名额

    5天免费试学

    基础班入门课程限时免费

    申请试学名额

    10天免费试学

    基础班入门课程限时免费

    申请试学名额