归并排序
这是一种非常高效的排序算法,使用到了递归的思想,就算法复杂度而言,和快排是相当的,某些时候,甚至比快排更合适,更高效。
将两个有序数组归并
如果能够实现将两个有序数组归并成一个有序数组,那么可以将4个8个16个N个有序数组归并成一个有序数组,那么对于length为N的数组,也就是N个元素为length为1的有序数组,对其归并也可实现排序,那么如何归并两个有序数组呢,或者说,如果一个数组分别实现了前后两个部分的有序,如何实现整个数组有序?
private Comparable[] aux[] = new Comparable[arr.length];//临时容器
/**
* arr[low]-arr[mid],arr[mid+1]-arr[high]分别有序,
* 实现arr[low]-arr[high]有序
*/
private void merge(Comparable[] arr, int low, int mid, int high){
int i = low;//前半部分的开始索引
int j = mid + 1;//后半部分的开始索引
//复制
for(int k = low; k <= high; k++){
aux[k] = arr[k];
}
for(int k = low; k <= high; k++){
if(i > mid) arr[k] = arr[j++];//左边用完了,取右边
else if(j>high) arr[k] = arr[i++];//右边用完了,取左边
else if(less(aux[i],aux[j])) arr[k] = aux[i++];//左边更小,取左边
else arr[k] = arr[j++]; //取右边
}
}
自顶向下的思路
如果一个数组,前半部分和后半部分分别有序,那么可以对数组的两部分顺序进行归并,使整个数组有序。
为了实现一个数组的前半部分有序,那么需要实现它(前半部分)的前后两个部分分别有序,进行归并之后,它可以实现有序。
……
对,这是一个递归。
public void sort(Comparable[] arr){
sort(arr, 0, arr.length - 1);
}
public void sort(Comparable[] arr, int low, int high){
if(low >= high) return;
int mid = low + (high - low) / 2;
sort(low,mid);//向左递归
sort(mid+1, high);//向右递归
merge(arr, mid, high);//归并左右,调用栈栈顶肯定是对单个元素的归并,如arr[10]和arr[11],但是这也是对两个有序数组归并
}
自底向上的思路
对于一个无序的数组,其前两个元素可以看做是数组中有序的两部分,三四个同理…前两个可以归并为一个有序的部分,三四个可以归并为一个有序的部分,这两个部分也可以归并为一个有序的部分,最终前四个元素成为有序的一部分,同理,整个数组也可以归并为一个有序的部分,即实现排序
public void sort(Comparable[] arr){
for(int size = 1; i < arr.length; size *= 2){
for(int low = 0; low < arr.length - size; low = low + size * 2)//low由0变成了2
merge(arr,low,low+size-1, Math.min(low + 2* size - 1, arr.length - 1))//mid可理解为左边排到哪里了,high可以理解为右边排到哪里了
}
}
总结
算法中应用递归,可以有效地比较与交换,归并排序对于部分有序的数组来说,非常高效。