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

网友投稿 345 2022-12-07


深入理解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)) performancKXagte 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.递归的将第一二三部分排序。

疑问:为啥不用泛型

{

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

疑问:为啥不用泛型

{

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

疑问:为啥不用泛型


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:@Validated验证List集合的方法示例
下一篇:JAVA SPI特性及简单应用代码实例
相关文章

 发表评论

暂时没有评论,来抢沙发吧~