目的:使用归并排序法对随机数组进行排序
归并排序思路:假设数组有n个数,先将其分为两半,再对这两半继续对半分隔...重复操作直到分隔后的小部分只有一个数。接着对这两个数进行归并操作,归并后得到一个有序的两个数组成的小数组,再将其与另一个有序的两个数组成的小数组进行归并,重复操作,直到所有数组有序。
之所以要先不断分隔,是为了左右两侧内部要保证有序,才可以进行归并操作。
话不啰嗦,还是直接上代码吧:
//归并排序法
public static void mergeSort(int[] array){
__mergeSort(array,0,array.length-1);
}
private static void __mergeSort(int[] array, int l, int r) {
if(l>=r){
return ;
}
int mid = (r-l)/2 + l;
__mergeSort(array,l,mid);
__mergeSort(array,mid+1,r);
__merge(array,l,r,mid);
}
private static void __merge(int[] array,int l,int r,int mid){
int[] temp = new int[r-l+1];
for(int i=l;i<=r;i++){
temp[i-l] = array[i];
}
int i = l;
int j = mid+1;
for(int k=l;k<=r;k++){
if(i>mid){
array[k] = temp[j-l];
j++;
}else if(j>r){
array[k] = temp[i-l];
i++;
}else if(temp[i-l]<temp[j-l]){
array[k] = temp[i-l];
i++;
}else{
array[k] = temp[j-l];
j++;
}
}
}
排序结果:
基础版的归并排序法还可以接着优化。
优化一:如果现在两侧小数组组成的一部分已经完全有序了,可以直接跳过归并操作
private static void __mergeSort(int[] array, int l, int r) {
if(l>=r){
return ;
}
int mid = (r-l)/2 + l;
__mergeSort(array,l,mid);
__mergeSort(array,mid+1,r);
if(array[mid]>array[mid])//如果左侧最大的数小于右侧最小的数,说明有序,不需要再归并了
__merge(array,l,r,mid);
}
优化二:当数组元素数量小的时候,可以进行优化版的插入排序法,提高在近乎有序的数组里的排序效率。
private static void __mergeSort(int[] array, int l, int r) {
if(r-l<=15){//如果个数小,其有序的可能性越大,尝试插入排序
insertionSortBetter(array,l,r);
return;
}
int mid = (r-l)/2 + l;
__mergeSort(array,l,mid);
__mergeSort(array,mid+1,r);
if(array[mid]>array[mid])//如果左侧最大的数小于右侧最小的数,说明有序,不需要再归并了
__merge(array,l,r,mid);
}
// 插入排序法优化
public static void insertionSortBetter(int[] array,int l,int r) {
for (int i = l+1; i <= r; i++) {
int e = array[i];
int j;
for (j = i; j > l && e < array[j - 1]; j--) {
array[j] = array[j - 1];
}
array[j] = e;
}
}
优化三:
将自顶向下的归并排序改为自底向上的归并排序,减少分隔的操作,不是经典的做法,这里就不列举了...