两路归并排序算法思路
分而治之(divide - conquer);每个递归过程涉及三个步骤
第一, 分解: 把待排序的 n 个元素的序列分解成两个子序列, 每个子序列包括 n/2 个元素.
第二, 治理: 对每个子序列分别调用归并排序MergeSort, 进行递归操作
第三, 合并: 合并两个排好序的子序列,生成排序结果.
算法实现
此算法的实现不像图示那样简单,现分三步来讨论。首先从宏观上分析,首先让子表表长 L=1 进行处理;不断地使 L=2*L ,进行子表处理,直到 L>=n 为止,把这一过程写成一个主体框架函数 mergesort 。然后对于某确定的子表表长 L ,将 n 个记录分成若干组子表,两两归并,这里显然要循环若干次,把这一步写成一个函数 mergepass ,可由 mergesort 调用。最后再看每一组(一对)子表的归并,其原理是相同的,只是子表表长不同,换句话说,是子表的首记录号与尾记录号不同,把这个归并操作作为核心算法写成函数 merge ,由 mergepass 来调用。假设我们有一个没有排好序的序列,那么首先我们使用分割的办法将这个序列分割成一个一个已经排好序的子序列,然后再利用归并的方法将一个个的子序列合并成排序好的序列。分割和归并的过程可以看下面的图例。
代码
/**
* @Author leijs
* @date 2021/8/17
*/
public class MergeSort {
public static void main(String[] args) {
int[] arr = {1, 4, 3, 6, 8, 4, 9, 6, 2};
int[] arr1 = mergeSort(arr);
for (int i = 0; i < arr1.length; i++) {
System.out.print(arr1[i]);
}
}
/**
* 分而治之的思想:每个递归过程分为三步:
* (1)分解:把待排序的n个元素分解成两个子序列,每个序列含n/2个元素
* (2)治理:对每个子序列分为调用归并并排序,进行递归操作
* (3)合并:合并两个排好序的子序列,生成排序结果
*
* @param arr
* @return
*/
public static int[] mergeSort(int[] arr) {
sort(arr, 0, arr.length - 1);
return arr;
}
private static int[] sort(int[] arr, int low, int high) {
int mid = (low + high) / 2;
if (low < high) {
sort(arr, low, mid);
sort(arr, mid + 1, high);
// 左右归并
merge(arr, low, mid, high);
}
return arr;
}
private static void merge(int[] arr, int low, int mid, int high) {
int[] temp = new int[high - low + 1];
int i = low;
int j = mid + 1;
int k = 0;
// 把较小的数先移到数组中
while (i <= mid && j <= high) {
if (arr[i] < arr[j]) {
temp[k++] = arr[i++];
} else {
temp[k++] = arr[j++];
}
}
// 把左边的剩余数移入数组
while (i <= mid) {
temp[k++] = arr[i++];
}
// 把右边剩余数移入数组
while (j <= high) {
temp[k++] = arr[j++];
}
// 把新数组中的数覆盖nums数组
for (int x = 0; x < temp.length; x++) {
arr[x + low] = temp[x];
}
}
}