教育行業(yè)A股IPO第一股(股票代碼 003032)

全國咨詢/投訴熱線:400-618-4000

java培訓(xùn):深入理解Java 中的Arrays.sort()方法

更新時(shí)間:2019年04月17日15時(shí)08分 來源:java培訓(xùn)機(jī)構(gòu)傳智播客 瀏覽次數(shù):

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

  Java的Arrays類中有一個(gè)sort()方法,該方法是Arrays類的靜態(tài)方法,在需要對數(shù)組進(jìn)行排序時(shí),非常的好用。

  但是sort()的參數(shù)有好幾種,基本上是大同小異,下面是以int型數(shù)組為例的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減序排序后順序");

  //要實(shí)現(xiàn)減序排序,得通過包裝類型數(shù)組,基本類型數(shù)組是不行滴

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

  Arrays.sort(integers, new Comparator()

  {

  /*

  * 此處與c++的比較函數(shù)構(gòu)成不一致

  * c++返回bool型,而Java返回的為int型

  * 當(dāng)返回值>0時(shí)

  * 進(jìn)行交換,即排序(源碼實(shí)現(xiàn)為兩樞軸快速排序)

  */

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

  //對數(shù)組的[2,6)位進(jìn)行排序

  Arrays.sort(ints2,2,6);

  for (int i=0;i

  {

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

  }

  }

  }

  排序結(jié)果如下

  增序排序后順序

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

  }

  從源碼中發(fā)現(xiàn),兩種參數(shù)類型的sort方法都調(diào)用了 DualPivotQuicksort.sort()方法

  繼續(xù)跟蹤源碼

  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;

  }

  }

  結(jié)合文檔以及源代碼,我們發(fā)現(xiàn),jdk中的Arrays.sort()的實(shí)現(xiàn)是通過所謂的雙軸快排的算法

  /**

  * 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的快排是一種雙軸快排,顧名思義:雙軸快排是基于兩個(gè)軸來進(jìn)行比較,跟普通的選擇一個(gè)點(diǎn)來作為軸點(diǎn)的快排是有很大的區(qū)別的,雙軸排序利用了區(qū)間相鄰的特性,對原本的快排進(jìn)行了效率上的提高,很大程度上是利用了數(shù)學(xué)的一些特性。。。。。嗯。。。反正很高深的樣子

  算法步驟

  1.對于很小的數(shù)組(長度小于27),會(huì)使用插入排序。

  2.選擇兩個(gè)點(diǎn)P1,P2作為軸心,比如我們可以使用第一個(gè)元素和最后一個(gè)元素。

  3.P1必須比P2要小,否則將這兩個(gè)元素交換,現(xiàn)在將整個(gè)數(shù)組分為四部分:

  (1)第一部分:比P1小的元素。

  (2)第二部分:比P1大但是比P2小的元素。

  (3)第三部分:比P2大的元素。

  (4)第四部分:尚未比較的部分。

  在開始比較前,除了軸點(diǎn),其余元素幾乎都在第四部分,直到比較完之后第四部分沒有元素。

  4.從第四部分選出一個(gè)元素a[K],與兩個(gè)軸心比較,然后放到第一二三部分中的一個(gè)。

  5.移動(dòng)L,K,G指向。

  6.重復(fù) 4 5 步,直到第四部分沒有元素。

  7.將P1與第一部分的最后一個(gè)元素交換。將P2與第三部分的第一個(gè)元素交換。

  8.遞歸的將第一二三部分排序。


推薦閱讀:

Java視頻教程

0 分享到:
和我們在線交談!