Arrays工具类(排序和查找)
注:以下代码及注释来自JAVA8源码
该类提供了一个静态工厂使arrays可以当作lists。(This class contains various methods for manipulating arrays (such as sorting and searching). This class also contains a static factory that allows arrays to be viewed as lists.)
一、类声明
类开始时就定义了一个常量,长度小于它时并行排序算法不会再对sort任务进行partition。该常量在parallelSort成员方法中使用。
public class Arrays {
/**
* The minimum array length below which a parallel sorting
* algorithm will not further partition the sorting task. Using
* smaller sizes typically results in memory contention across
* tasks that makes parallel speedups unlikely.
*/
private static final int MIN_ARRAY_SORT_GRAN = 1 << 13;
// Suppresses default constructor, ensuring non-instantiability.
private Arrays() {}
...
二、排序方法
注释中解释了其使用了双基准的快速排序,比传统的单基准的快速排序要快
/**
* Sorts the specified array into ascending numerical order.
*
* <p>Implementation note: The sorting algorithm is a Dual-Pivot Quicksort
* by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This 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.
*
* @param a the array to be sorted
*/
public static void sort(int[] a) {
DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
}
DualPivotQuicksort也是java.util中的一个工具类,并且声明为final不允许继承。final class DualPivotQuicksort {…}
由于代码过长,这里只给出声明和算法介绍
/**
* Sorts the specified range of the array using the given
* workspace array slice if possible for merging
*
* @param a the array to be sorted
* @param left the index of the first element, inclusive, to be sorted
* @param right the index of the last element, inclusive, to be sorted
* @param work a workspace array (slice)
* @param workBase origin of usable space in work array
* @param workLen usable size of work array
*/
static void sort(int[] a, int left, int right,
int[] work, int workBase, int workLen) {...}
参数里提供了一个workspace array slice以供merge的时候使用。在Arrays.sort()的调用中此值设置为null,这里不做讨论。
merge sort中最大的数量设置为67,最大的长度设置为33。
重点分析一下以下代码:
// Use Quicksort on small arrays
if (right - left < QUICKSORT_THRESHOLD) {
sort(a, left, right, true);
return;
}
如果小于286个数的时候用该类中定义的4参数quicksort方法sort(int[] a, int left, int right, boolean leftmost){}调用后结果直接返回。在4参数quicksort方法内部又分情形
1)如果<47个数的时候(tiny arrays)用插入排序:最后一个参数leftmost是说这个是不是数组最左边的位置( indicates if this part is the leftmost in the range)
2)如果>=47个数用快速排序,取数组长度的1/7长度作为seventh变量,取数组中间位置作为e3变量,最终求出e1、e2、e3、e4、e5五个位置将数组大致平均分为六份,将这五个位置的数按从小到大排好序。
int pivot1 = a[e2];
int pivot2 = a[e4];
选取两个基准
a[e2] = a[left];
a[e4] = a[right];
然后分情况用快速排序递归调用4参数的sort();
三、查找方法
(对于有序数组的查找,不多说直接上代码"二分查找")
使用了>>>1操作来设置中间结点,key比中间结点大,重置low值;key比中间结点小,重置high值。找不到返回负数-(low+1)
public static int binarySearch(int[] a, int fromIndex, int toIndex, int key) {
rangeCheck(a.length, fromIndex, toIndex); //检查Index范围是否合法
return binarySearch0(a, fromIndex, toIndex, key);
}
// Like public version, but without range checks.
private static int binarySearch0(int[] a, int fromIndex, int toIndex, int key) {
int low = fromIndex;
int high = toIndex - 1;
while (low <= high) {
int mid = (low + high) >>> 1; //无符号右移1位,高位补0
int midVal = a[mid];
if (midVal < key)
low = mid + 1;
else if (midVal > key)
high = mid - 1;
else
return mid; // key found
}
return -(low + 1); // key not found.
}
四、复制方法 Arrays.copyOf()
在ArrayList的构造方法、grow方法、clone方法都调用了elementData = Arrays.copyOf(elementData, size, Object[].class); 其中elementData声明为transient Object[] elementData;
Arrays.copyOf使用泛型声明了一个静态方法,会返回一份新的copy。调用了System.arraycopy本地方法。源码如下:
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
@SuppressWarnings("unchecked")
T[] copy = ((Object)newType == (Object)Object[].class)
? (T[]) new Object[newLength]
: (T[]) Array.newInstance(newType.getComponentType(), newLength);
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength)); //调用了本地方法(JNI),用C语言实现底层
return copy;
}