public static void merge(int[] a,int lo,int mid,int hi){
int i = lo ,j = mid + 1;
for(int k=lo;k<=hi;k++){
aux[k] = a[k];
}
for(int k=lo;k<=hi;k++){
if(i > mid) { a[k] = aux[j++]; //左边越界,放右边元素
}else if(j > hi){ a[k] = aux[i++]; //右边越界,放左边元素
}else if(less(aux[i],aux[j])){ a[k] = aux[i++]; //主要比较操作,放入较小元素
}else{ a[k] = aux[j++]; //同上
}
}
}
既然是归并排序,当然要把两个有序的小数组归并为一个有序的大数组。其中:i和j为两个数组的起点;再利用辅助数组aux,在数组a上排序。
下面有两种归并排序的实现:自顶向下 ; 自底向上
1 自顶向下:
public static void mergeSort(int[] a){
aux = new int[a.length];
mergeSort(a,0,a.length-1); //自顶向下
}
public static void mergeSort(int[] a,int lo,int hi){
if(hi <=lo) {
return;
}
int mid = lo + (hi-lo) / 2;
mergeSort(a,lo,mid); //排序左半边数组
mergeSort(a,mid+1,hi); //排序右半边数组
merge(a,lo,mid,hi); //调用归并
}
在mergeSort函数中,先申请了一个固定长度的aux数组(这个函数只执行了一次).再调用带lo和hi参数的mergeSort函数。
思想:利用嵌套先将大数组拆至长度为一的小数组,再归并为有序的大数组。
2 自底向上:
public static void mergeSort(int[] a){
aux = new int[a.length];
for(int sz=1;sz<a.length;sz = sz+sz){
for(int lo=0;lo<a.length-sz;lo+=sz+sz){ //自底向上
merge(a,lo,lo+sz-1,Math.min(lo+sz+sz-1, a.length-1));
}
}
}
在mergeSort函数中,利用循环将直接从长度为1的小数组开始进行归并。下一次循环小数组长度为2,4,8,16....。
归并排序复杂度:
在此排序算法中用到了辅助空间保存临时数组。所以空间复杂度不是最优;其最坏的时间复杂度~NlgN。