归并排序先递归地将数组分成两半分别排序,然后将结果归并起来,遵循分冶模式:
- 分解:分解待排序的n个元素的序列成各具n/2个元素的两个子序列。
- 解决:使用归并排序递归地排列两个子序列。
- 合并:合并两个已排序的子序列(归并排序的关键步骤)。
时间复杂度为O(NlogN),空间复杂度O(N),稳定的排序(如果一个排序算法能够保留数组中重复元素的相对位置则被称为是稳定的)。
经数学证明,所有基于比较的排序算法的时间复杂度的下界为O(NlogN)。
java.util.Arrays.sort()对基本数据类型使用三向切分的快速排序,对引用类型使用归并排序。
public class Merge {
private static int[] temp;
public static void sort(int[] a){
temp = new int[a.length];
sort(a, 0, a.length - 1);
}
/**
* 自顶向下的归并排序
* 依次将子数组排序,然后通过归并两个子数组来将整个数组排序。
*/
private static void sort(int[] a, int low, int high){
//将数组a[low...high]排序
if(high <= low)
return;
int mid = low + (high - low) / 2;
sort(a, low, mid);//将左半边排序
sort(a, mid + 1, high);//将右半边排序
merge(a, low, mid, high);//归并结果
}
/**
* 先将所有元素复制到temp[]中,然后再归并回a[]。
* 当左半边比较完元素或者右半边的当前元素小于左半边时,取右半边的元素;
* 当右半边比较完元素或者左半边的当前元素小于右半边时,取左半边的元素。
*/
private static void merge(int[] a, int low, int mid, int high){
//将a[low...mid]和a[mid+1...high]归并
int i = low;
int j = mid + 1;
for(int k = low; k <= high; k++){
temp[k] = a[k];
}
for(int k = low; k <= high; k++){
if(i > mid){
a[k] = temp[j++];
}else if(j > high){
a[k] = temp[i++];
}else if(temp[i] > temp[j]){
a[k] = temp[j++];
}else{
a[k] = temp[i++];
}
}
}
/**
* 自底向上的归并排序:
* 先归并那些微型数组,然后再成对归并得到子数组,
* 如此这般,直到将整个数组归并在一起。
*/
public static void sort2(int[] a){
int N = a.length;
temp = new int[N];
for(int i = 1; i < N; i = i + i){
for(int low = 0; low < N - i; low += i + i){
merge(a, low, low+i-1, Math.min(low+i+i-1, N-1));
}
}
}
}