前言
(1)Arrays包含用來操作數組(比如排序和搜索)的各種方法。Arrays提供的方法都是靜態方法,Arrays的構造函數是私有的,也就是不能被實例化。
(2)包含一個允許將數組作爲列表來查看的靜態工廠。
(3)除非特別註明,否則如果指定數組引用爲 null,則此類中的方法都會拋出 NullPointerException。
(4)涉及的排序算法簡單介紹
1> Java1.7之前的快排:在Java1.7之前的快排只是普通的快排,跟我們今天要研究的快排不一樣,性能也差了許多,但其中對快排所做的各種優化我們依然是可以學習的。
Java1.7的快排:Java1.7的快排是一種雙軸快排,顧名思義:雙軸快排是基於兩個軸來進行比較,跟普通的選擇一個點來作爲軸點的快排是有很大的區別的。算法是由Vladimir Yaroslavskiy在2009年研究出來的,並在2011年發佈在了Java1.7。由於Arrays.sort對於數組的排序做了各種各樣的優化,並且大多數優化和我們今天要研究的雙軸排序無關,所以我們暫且略過,以後有時間研究Arrays源碼的時候我們再進行分析。
2>TimSort是mergeSort的一種改進,引入binarySort進行子數組的排序,實現優化(原來的子數組排序是採用的選擇排序),每次進行子數組合並的時候會進行一些特殊的處理來進行對一些特殊情況的優化。
TimSort算法是一種起源於歸併排序和插入排序的混合排序算法,設計初衷是爲了在真實世界中的各種數據中可以有較好的性能。該算法最初是由Tim Peters於2002年在Python語言中提出的。
TimSort 是一個歸併排序做了大量優化的版本。對歸併排序排在已經反向排好序的輸入時表現O(n2)的特點做了特別優化。對已經正向排好序的輸入減少回溯。對兩種情況混合(一會升序,一會降序)的輸入處理比較好。
在jdk1.7之後,Arrays類中的sort方法有一個分支判斷,當LegacyMergeSort.userRequested爲true的情況下,採用legacyMergeSort,否則採用ComparableTimSort。並且在legacyMergeSort的註釋上標明瞭該方法會在以後的jdk版本中廢棄,因此以後Arrays類中的sort方法將採用ComparableTimSort類中的sort方法。
注:
此類中所含方法的文檔都包括對實現 的簡短描述。應該將這些描述視爲實現注意事項,而不應將它們視爲規範 的一部分。實現者應該可以隨意替代其他算法,只要遵循規範本身即可。(例如,sort(Object[]) 使用的算法不必是一個合併排序算法,但它必須是穩定的。)
源碼
public class Arrays {//類的構造函數是私有的
private Arrays() {}
........
//整數數組的排序,升序排列,如果需要降序,則自行處理
public static void sort(int[] a) {
// JDK1.7的排序算法使用了DulaPivotQuickSort算法,該算法是快排的一種變種算法
DualPivotQuicksort.sort(a);
}
//基本類型的排序都使用該排序算法
public static void sort(double[] a) {
DualPivotQuicksort.sort(a);
}
//對象的排序,對象必須是可比較的,即必須實現Compareable接口
public static void sort(Object[] a) {
if (LegacyMergeSort.userRequested)
legacyMergeSort(a);//用合併排序算法,需要額外的一倍空間
else
ComparableTimSort.sort(a);//用TimSort算法
}
//合併排序算法的實現,需額外的dest空間
private static void mergeSort(Object[] src, Object[] dest,int low,int high, int off) {
int length = high - low;
//在小數據集上面之間用插入排序算法,即長度小於7時
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--) //用Comparable的排序接口
swap(dest, j, j-1);//交換兩個元素
return;
}
//元素長度大於7時,按合併排序算法進行排序
int destLow = low;
int destHigh = high;
low += off;
high += off;
int mid = (low + high) >>> 1;
//從low到mid的元素進行合併排序
mergeSort(dest, src, low, mid, -off);
//從mid到high的元素進行合併排序
mergeSort(dest, src, mid, high, -off);
//如果兩部分已經有序,則執行合併即可
if (((Comparable)src[mid-1]).compareTo(src[mid]) <= 0) {
System.arraycopy(src, low, dest, destLow, length);
return; }
//進行合併操作
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++];
}
}
//二分搜索算法,要求a是有序的
public static int binarySearch(long[] a, long key) {
return binarySearch0(a, 0, a.length, key);
}
//執行二分搜索
private static int binarySearch0(long[] a, int fromIndex, int toIndex,
long key) {
int low = fromIndex;
int high = toIndex - 1;
while (low <= high) {
int mid = (low + high) >>> 1;//用移位運算實現除法
long 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.
}
//對象的二分搜索
private static int binarySearch0(Object[] a, int fromIndex, int toIndex,
Object key) {
int low = fromIndex;
int high = toIndex - 1;
while (low <= high) {
int mid = (low + high) >>> 1;
Comparable midVal = (Comparable)a[mid];
int cmp = midVal.compareTo(key);//用Compareable的排序接口
if (cmp < 0)
low = mid + 1;
else if (cmp > 0)
high = mid - 1;
else
return mid; // key found
}
return -(low + 1); // key not found.
}
//數組的比較算法
public static boolean equals(byte[] a, byte[] a2) {
if (a==a2)//指向同一個值
return true;
if (a==null || a2==null)
return false;
int length = a.length;
if (a2.length != length)//數組長度的比較
return false;
for (int i=0; i<length; i++)
if (a[i] != a2[i])//值的比較
return false;
return true;
}
//填充算法,Java沒有類似C的memset,不然效率更高
public static void fill(char[] a, char val) {
for (int i = 0, len = a.length; i < len; i++)
a[i] = val;
}
//計算Hash值的算法
public static int hashCode(byte a[]) {
if (a == null)
return 0;
int result = 1;
for (byte element : a)
result = 31 * result + element;//使用了Time31的Hash算法
return result;
}