二路归并排序的基本思想:设 n 个待排记录,看成是 n 个有序的子序列,每个子序列的长度为 1 ,对此进行两两归并,得到 n/2 个长度为 2 或 1 的有序子序列;再继续两两归并,得到 n/4 个有序子序列,重复进行直至得到一个长度为 n 的有序序列为止。

public class MergeSort {
public static void main(String[] args) {
//int[] arr = { 9, 8, 7, 6, 5, 4, 3, 2, 1 };
int[] arr = { 21, 25, 49, 25, 93, 62, 72, 8, 37, 16, 54 };
display("原始数据: ", arr);
mainMerge(arr, arr.length);
display("排序结果: ", arr);
}
// 显示
public static void display(String str, int[] arr) {
System.out.println(str);
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
System.out.println();
}
// 归并排序主算法:
// 第一趟: arr归并到arrDest;
// 第二趟: arrDest归并到arr; ......,需偶数趟。
// 若最后一趟 len>=n,则arrDest直接复制到arr。
public static void mainMerge(int[] arr, int n) {
// 对数组arr[n]中的记录进行归并排序
int[] arrDest = new int[n];
int len = 1;
while (len < n) {
oneMerge(arr, arrDest, n, len);
len *= 2;
oneMerge(arrDest, arr, n, len);
len *= 2;
}
// 清空临时数组
arrDest = null;
}
// 一趟归并排序算法:把arr[n]中长度为len的有序表两两归并到arrDest[n]
public static void oneMerge(int[] arr, int[] arrDest, int n, int len) {
int p = 0; // 一对待合并表的第一个元素的位置
// 循环两两归并
while (p + 2 * len - 1 <= n - 1) {
// twoMerge(int[] arr, int[] arrDest, int s, int m, int t)
// 将有序表arr[s..m] 和 arr[m+1..t] 归并为有序表arrDest[s..t]
twoMerge(arr, arrDest, p, p + len - 1, p + 2 * len - 1);
p += 2 * len;
}
if (p + len <= n - 1) {
// 归并最后两个长度不等的有序表
twoMerge(arr, arrDest, p, p + len - 1, n - 1);
} else {
// 复制最后剩下的一个有序表
for (int i = p; i <= n - 1; i++) {
arrDest[i] = arr[i];
}
}
}
// 二路归并算法:将有序表 arr[s..m] 和 arr[m+1..t] 归并为有序表arrDest[s..t]
public static void twoMerge(int[] arr, int[] arrDest, int s, int m, int t) {
int i, j, k;
i = s;
j = m + 1;
k = s; // 分别指向每个表的起始位置
// 两个有序表的归并
while (i <= m && j <= t) {
if (arr[i] <= arr[j]) {
arrDest[k] = arr[i];
i++;
k++;
} else {
arrDest[k] = arr[j];
j++;
k++;
}
}
// 复制第一个有序表中未归并的元素
while (i <= m) {
arrDest[k] = arr[i];
i++;
k++;
}
// 复制第二个有序表中未归并的元素
while (j <= t) {
arrDest[k] = arr[j];
j++;
k++;
}
}
}