Arrays这边主要看方法实现
一.方法实现
1.binarySearch0
这边就直接看支持泛型的binarySearch0,因为Arrays里面有很多binarySearch的重载,支持泛型的应该是最能看出问题的
二分查找的默认前提是排序好的数组
直接上代码:
/**
* 前面的调用函数做了一些列的长度检查,这边就是直接的二分法查找操作 -- 二分法的前提是排序好得数组
* @param a 被查找的数组
* @param fromIndex 从哪个位置开始查找
* @param toIndex 查找结束的位置
* @param key 要查找的元素
* @param c 比较规则,比如int就是 > = <这样
* @param <T> 查找泛型
* @return 返回查找到的元素
*/
private static <T> int binarySearch0(T[] a, int fromIndex, int toIndex,
T key, Comparator<? super T> c) {
//1.如果没有匹配规则,就按照Object的方式去匹配
if (c == null) {
return binarySearch0(a, fromIndex, toIndex, key);
}
//2.设值低位和高位
int low = fromIndex;
int high = toIndex - 1;
//3.当低位一直小于高位的时候,循环
while (low <= high) {
//4.找到中间位置下标和对应元素
int mid = (low + high) >>> 1;
T midVal = a[mid];
//5.比较
int cmp = c.compare(midVal, key);
//6.如果小则低位 = 中间位置+1;如果大则高位 = 中间位置-1;相等则返回
if (cmp < 0)
low = mid + 1;
else if (cmp > 0)
high = mid - 1;
else
return mid; // key found
}
return -(low + 1); // key not found.
}
2.sort
sort方法这边有两种实现,一种是归并排序,一种是timsort;我们分别来看两种排序方法
public static <T> void sort(T[] a, Comparator<? super T> c) {
if (c == null) {
sort(a);
} else {
//这边主要关注两个排序方法
//1.merge sort是归并排序,通过System.setProperty("java.util.Arrays.useLegacyMergeSort", "true");设置
//归并排序它的时间复杂度(最优、平均、最差)都是O(n log n),但是需要整块数组空间参与
//2.tim sort是归并排序+插入排序的优化
if (LegacyMergeSort.userRequested)
legacyMergeSort(a, c);
else
TimSort.sort(a, 0, a.length, c, null, 0, 0);
}
}
1.mergesort,归并排序
归并排序的排序思想就是分堆,然后堆之间排序,通过递归实现所有堆的排序,他的算法过程大概是这样的:
- 大数组进来(长度大于7),从中间切开,分成两个中数组
- 递归调用每个中数组(长度大于7),从中间切开,分成两个小数组
- 小数组(长度小于7),进行快速排序,返回
- 回到中数组,这边有一个快排的优化,就是判断两个小数组,前一个的最后一位是否小于后一个的第一位,如果是,说明无需排序,直接copy即可
- 上述不满足的话,则循环小数组,从第一位开始比较,小的元素添加到新数组,下标后移,直到结束
- 重复上述步骤,直到递归结束
图示:
private static void mergeSort(Object[] src,
Object[] dest,
int low, int high, int off,
Comparator c) {
int length = high - low;
// 1.如果数组长度小于7,使用插入排序
if (length < INSERTIONSORT_THRESHOLD) {
for (int i=low; i<high; i++)
for (int j=i; j>low && c.compare(dest[j-1], dest[j])>0; j--)
swap(dest, j, j-1);
return;
}
//2.把数组拆分成两个小数组,进入递归
int destLow = low;
int destHigh = high;
low += off;
high += off;
int mid = (low + high) >>> 1;
mergeSort(dest, src, low, mid, -off, c);
mergeSort(dest, src, mid, high, -off, c);
//3.这边是对快排的结果做一个优化,如果直接是有序的,只要copy数组就行
if (c.compare(src[mid-1], src[mid]) <= 0) {
System.arraycopy(src, low, dest, destLow, length);
return;
}
//4.低位和mid位置进行比较,因为归并之后,大数组包含两个小数组,前后两个小数组是各自有序的
for(int i = destLow, p = low, q = mid; i < destHigh; i++) {
if (q >= high || p < mid && c.compare(src[p], src[q]) <= 0)
dest[i] = src[p++];
else
dest[i] = src[q++];
}
}
2.timsort:归并和快排的结合
不是很能理解,以后再补充吧