“归并”的含义是将两个或两个以上的有序表组合成一个新的有序表。假定待排序表含有n个记录,则可以看成是n歌有序的子表,每个子表长度为1,然后两两归并,得到⌈n/2⌉个长度为2或1的有序表,再两两归并,… … 如此重复,直到合并成一个长度为n的有序表为止,这种排序方法称为2-路归并排序。如下图的例子:
public class MergeSort {
public static void main(String[] args) {
int arr[] = { 32, 17, 4, 50, 11, 36, 45, 23, 8, 28, 41 };
MergeSort.mergeSort(arr, 0, arr.length - 1);
}
// 递归排序
public static void mergeSort(int[] arr, int left, int right) {
if (left < right) {
int mid = (left + right) / 2;// 从中间划分两个子序列
mergeSort(arr, left, mid);// 对左侧子序列进行递归排序
mergeSort(arr, mid + 1, right);// 对右侧子序列进行递归排序
merge(arr, left, mid, right);// 归并
}
}
/**
* 表arr的两段arr[low...mid]和arr[mid+1...high]各自有序,将它们合并成一个有序表
*
* @param arr
* @param low
* @param mid
* @param high
*/
public static void merge(int[] arr, int left, int center, int right) {
int low = left;
int mid = center + 1;
int tmp = left;
int[] tmpArr = new int[arr.length];
while (left <= center && mid <= right) {
// 从两个数组中取出最小的放入中间数组
if (arr[left] <= arr[mid]) {
tmpArr[low++] = arr[left++];
} else {
tmpArr[low++] = arr[mid++];
}
}// while
// 剩余部分依次放入中间数组
while (left <= center) {
tmpArr[low++] = arr[left++];
}
while (mid <= right) {
tmpArr[low++] = arr[mid++];
}
// 将中间数组中的内容复制回原数组
while (tmp <= right) {
arr[tmp] = tmpArr[tmp++];
}
}
}
2-路归并排序算法性能分析;
1)空间效率:merge()操作中,由于辅助空间刚好要占用n个单元,但每一趟归并后这些空间就被释放了,所以归并排序的空间复杂度为O(n)。
2)时间效率:每一趟归并排序的时间复杂度为O(n),共需⌈log2n⌉趟归并,所以时间复杂度为O(nlog2n)。
3)稳定性:由于merge()方法不会改变相同关键字记录的相对次序,所以2-路归并排序是一个稳定的算法。