您的位置:首页 > 编程语言 > Java开发

java Arrays.sort 源码分析

2012-06-05 22:05 417 查看
java Arrays 类中的sort排序提供了对基本类型(int、long、short)和对象类型的排序。基本类型的排序采用的是调优的

快速排序。对象的排序采用的是改进的归并排序。下面将分别介绍这两种排序方式。

源码中的快速排序,主要做了以下几个方面的优化:

1)当待排序的数组中的元素个数较少时,源码中的阀值为7,采用的是插入排序。尽管插入排序的时间复杂度为0(n^2),但是当数组元素较少时,插入排序 优于快速排序,因为这时快速排序的递归操作影响性能。

2)较好的选择了划分元。能够将数组分成大致两个相等的部分,避免出现最坏的情况。例如当数组有序的的情况下,选择第一个元素作为划分元,将使得算法的时间复杂度达到O(n^2).

源码中选择划分元的方法:

当数组大小 为size<=7时 ,取数组中间元素作为划分元。

当数组大小 7<size<=40时,取首、中、末 三个元素中间大小的元素作为划分元。

当数组大小 size>40 时 ,从待排数组中较均匀的选择9个元素,选出一个伪中数做为划分元。

3)根据划分元 v ,形成不变式 v* (<v)* (>v)* v*

普通的快速排序算法,经过一次划分后,将划分元排到素组较中间的位置,左边的元素小于划分元,右边的元素大于划分元,而没有将与划分元相等的元素放在其附近,这一点,在Arrays.sort()中得到了较大的优化。

举例:15、93、15、41、6、15、22、7、15、20

因 7<size<=40,所以在15、6、和20 中选择v = 15 作为划分元。

经过一次换分后: 15、15、7、6、41、20、22、93、15、15. 与划分元相等的元素都移到了素组的两边。

接下来将与划分元相等的元素移到数组中间来,形成:7、6、15、15、15、15、41、20、22、93.

最后递归对两个区间进行排序[7、6]和[41、20、22、93].

部分源码:

public class Arrays {

/**

* Sorts the specified array of ints into ascending numerical order.

* The sorting algorithm is a tuned quicksort, adapted from Jon

* L. Bentley and M. Douglas McIlroy's "Engineering a Sort Function",

* Software-Practice and Experience, Vol. 23(11) P. 1249-1265 (November

* 1993). This algorithm offers n*log(n) performance on many data sets

* that cause other quicksorts to degrade to quadratic performance.

*

* @param a the array to be sorted

*/

public static void sort(int a[]){

sort1(a,0,a.length);

}

//对指定范围的数组按升序排序,从fromIndex 到 toIndex

public static void sort(int[] a, int fromIndex, int toIndex) {

rangeCheck(a.length, fromIndex, toIndex); // 检查待排数组的范围是否合法。

sort1(a, fromIndex, toIndex-fromIndex);

}

/**

* 对指定的整形子数组进行升序排序。

*/

private static void sort1(int x[], int off, int len) {

//小数组时采用插入排序

if (len < 7) {

for (int i=off; i<len+off; i++)

for (int j=i; j>off && x[j-1]>x[j]; j--)

swap(x, j, j-1);

return;

}

// Choose a partition element, v

int m = off + (len >> 1); // size=7 时 取中间元素作为划分元

if (len > 7) { // 7<size<=40 取首中末中的中间大小的元素作为划分元

int l = off;

int n = off + len - 1;

if (len > 40) { // 从9个数中选择一个伪中数作为划分元。

int s = len/8;

l = med3(x, l, l+s, l+2*s);

m = med3(x, m-s, m, m+s);

n = med3(x, n-2*s, n-s, n);

}

m = med3(x, l, m, n); //取出中间大小的元素的位置。

}

int v = x[m];

// Establish Invariant: v* (<v)* (>v)* v*

int a = off, b = a, c = off + len - 1, d = c;

while(true) {

while (b <= c && x[b] <= v) {

if (x[b] == v)

swap(x, a++, b);

b++;

}

while (c >= b && x[c] >= v) {

if (x[c] == v)

swap(x, c, d--);

1 c--;

}

if (b > c)

break;

swap(x, b++, c--);

}

// Swap partition elements back to middle

int s, n = off + len;

s = Math.min(a-off, b-a ); vecswap(x, off, b-s, s);

s = Math.min(d-c, n-d-1); vecswap(x, b, n-s, s);

// Recursively sort non-partition-elements

if ((s = b-a) > 1)

sort1(x, off, s);

if ((s = d-c) > 1)

sort1(x, n-s, s);

}

/**

* Swaps x[a] with x[b].

*/

private static void swap(int x[], int a, int b) {

int t = x[a];

x[a] = x[b];

x[b] = t;

}

/**

* Swaps x[a .. (a+n-1)] with x[b .. (b+n-1)].

*/

private static void vecswap(int x[], int a, int b, int n) {

for (int i=0; i<n; i++, a++, b++)

swap(x, a, b);

}

/**

* Returns the index of the median of the three indexed integers.

*/

private static int med3(int x[], int a, int b, int c) {

return (x[a] < x[b] ?

(x[b] < x[c] ? b : x[a] < x[c] ? c : a) :

(x[b] > x[c] ? b : x[a] > x[c] ? c : a));

}

/**

* Sorts the specified array of objects into ascending order, according to

* the {@linkplain Comparable natural ordering}

* of its elements. All elements in the array

* must implement the {@link Comparable} interface. Furthermore, all

* elements in the array must be <i>mutually comparable</i> (that is,

* <tt>e1.compareTo(e2)</tt> must not throw a <tt>ClassCastException</tt>

* for any elements <tt>e1</tt> and <tt>e2</tt> in the array).<p>

*

* This sort is guaranteed to be <i>stable</i>: equal elements will

* not be reordered as a result of the sort.<p>

*

* The sorting algorithm is a modified mergesort (in which the merge is

* omitted if the highest element in the low sublist is less than the

* lowest element in the high sublist). This algorithm offers guaranteed

* n*log(n) performance.

*

* @param a the array to be sorted

* @throws ClassCastException if the array contains elements that are not

* <i>mutually comparable</i> (for example, strings and integers).

*/

//对对象进行排序。

public static void sort(Object[] a) {

Object[] aux = (Object[])a.clone();

mergeSort(aux, a, 0, a.length, 0);

}

//对数组中指定范围的对象进行排序

public static void sort(Object[] a, int fromIndex, int toIndex) {

rangeCheck(a.length, fromIndex, toIndex);

Object[] aux = copyOfRange(a, fromIndex, toIndex);

mergeSort(aux, a, fromIndex, toIndex, -fromIndex);

}

private static final int INSERTIONSORT_THRESHOLD = 7;//调优参数

/**

* 将指定范围的对象数组按自然顺序升序排序。

* src[] 原待排数组

* dest[] 目的待排数组

* low 待排数组的下界位置

* high 待排数组的上界位置

* off 从数组的第off个元素开始排序

*/

private static void mergeSort(Object[] src,

Object[] dest,

int low,

int high,

int off) {

int length = high - low;

// Insertion sort on smallest arrays

if (length < INSERTIONSORT_THRESHOLD) {

for (int i=low; i<high; i++)

for (int j=i; j>low &&

((Comparable) dest[j-1]).compareTo(dest[j])>0; j--)

swap(dest, j, j-1);

return;

}

// Recursively sort halves of dest into src

int destLow = low;

int destHigh = high;

low += off;

high += off;

int mid = (low + high) >>> 1;

mergeSort(dest, src, low, mid, -off);

mergeSort(dest, src, mid, high, -off);

// If list is already sorted, just copy from src to dest. This is an

// optimization that results in faster sorts for nearly ordered lists.

// 如果列表已经排好序了,只要将src 拷贝到dest。这对接近已排序的列表做了优化。

if (((Comparable)src[mid-1]).compareTo(src[mid]) <= 0) {

System.arraycopy(src, low, dest, destLow, length);

return;

}

// Merge sorted halves (now in src) into dest

for(int i = destLow, p = low, q = mid; i < destHigh; i++) {

if (q >= high || p < mid && ((Comparable)src[p]).compareTo(src[q])<=0)

dest[i] = src[p++];

else

dest[i] = src[q++];

}

}

/**

* Swaps x[a] with x[b].

*/

private static void swap(Object[] x, int a, int b) {

Object t = x[a];

x[a] = x[b];

x[b] = t;

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: