2019-06-16
思想:
- 先实现一个数组的中间位置“断裂”为两个子数组,利用索引实现,一直到每一个都被分开;
- 直到最后两个数据都被分开后,然后借助辅助数组实现排序与合并操作;
- 最后递归返回到最初的时候,便实现了整个递归排序
归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的,然后再把有序子序列合并为整体有序序列[2]。
代码实现如下:
public class MergeSort {
public void MergeSort(int[] arr) {
Divide(arr, 0, arr.length - 1);
}
//将数组array分裂为每组只有一个元素
public void Divide(int[] array, int left, int right) { //中间递归
//将数组array分裂为一组只有一个元素时停止
if (left == right) return;
//获取该区间的中间值
int mid = (left + right) / 2;
//将区间平均分成两半,对左右区间分别进行归并排序
Divide(array, left, mid);
Divide(array, mid + 1, right);
//此时已经将数组array分裂为每组只有一个元素
//由于此时左右区间分别有序
//如果归并排序后的左区间最后一个元素大于右区间第一个元素,需要合并为整体有序
if (array[mid] > array[mid + 1]) {
//将左区间与右区间合并形成有序数组
merge(array, left, mid, right);
}
}
//两路有序归并为一路;
// 即有序的arr[left, mid]和有序的arr[mid+1, right]归并为有序的arr[left, right]
public void merge(int[] array, int left, int mid, int right) {
//用来存储原数组array的临时数组
int[] temp = new int[right - left + 1];
//将原数据拷贝到临时数组
// System.arraycopy(array, left, temp, 0, right - left + 1);
for (int i = left; i <= right; i++) {
temp[i - left] = array[i];
}
//i为左区间起点,j为右区间起点
int i = left, j = mid + 1;
for (int k = left; k <= right; k++) {
if (i > mid) { //左区间的数已存完
array[k] = temp[j - left]; //将右区间剩下的数存到数组
j++; //右区间下标移动
} else if (j > right) { //右区间的数已存完
array[k] = temp[i - left]; //将左区间剩下的数存到数组
i++; //左区间下标移动
} else if (temp[i - left] < temp[j - left]) { //左区间的值小于右区间
array[k] = temp[i - left]; //将左区间的值存入数组
i++; //左区间下标移动
} else { //右区间的值小于左区间
array[k] = temp[j - left];
j++; //右区间下标移动
}
}
}
@Test
public void testFunction() {
int a[] = {35, 11, 24, 52, 77, 69, 8, 3, 6, 62};
int b[] = {7, 9, 3, 2, 5, 8, 6};
MergeSort(a);
MergeSort(b);
System.out.println(Arrays.toString(a));
System.out.println(Arrays.toString(b));
}
}
/*
Output:
[3, 6, 8, 11, 24, 35, 52, 62, 69, 77]
[2, 3, 5, 6, 7, 8, 9]
*/
第二种写法:
/**
* @Date: 2019/8/8 16:12
* @Description: 与MergeSort仅仅是merge()实现上稍稍不同
*/
public class MergeSort2 {
public void MergeSort_Recursion(int[] arr) {
mergeSort(arr, 0, arr.length - 1);
}
public void mergeSort(int[] a, int low, int high) {
int mid = (low + high) / 2;
if (low < high) {
// 左边
mergeSort(a, low, mid);
// 右边
mergeSort(a, mid + 1, high);
// 左右归并
merge(a, low, mid, high);
// System.out.println(Arrays.toString(a));
}
}
public void merge(int[] a, 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 (a[i] < a[j])
temp[k++] = a[i++];
else
temp[k++] = a[j++];
}
// 把左边剩余的数移入数组
while (i <= mid) {
temp[k++] = a[i++];
}
// 把右边边剩余的数移入数组
while (j <= high) {
temp[k++] = a[j++];
}
// 把新数组中的数覆盖a数组
for (int m = 0; m < temp.length; m++) {
a[m + low] = temp[m];
}
}
@Test
public void testMergeSort() {
int a[] = {35, 11, 24, 52, 77, 69, 8, 3, 6, 62};
int b[] = {7, 9, 3, 2, 5, 8, 6};
MergeSort_Recursion(a);
MergeSort_Recursion(b);
System.out.println(Arrays.toString(a));
System.out.println(Arrays.toString(b));
}
}
/*
Output:
[3, 6, 8, 11, 24, 35, 52, 62, 69, 77]
[2, 3, 5, 6, 7, 8, 9]
*/