归并排序

2019-06-16
基本思想.PNG

排序过程.PNG

一趟归并.PNG

递归形式的归并.PNG

思想:

  1. 先实现一个数组的中间位置“断裂”为两个子数组,利用索引实现,一直到每一个都被分开;
  2. 直到最后两个数据都被分开后,然后借助辅助数组实现排序与合并操作;
  3. 最后递归返回到最初的时候,便实现了整个递归排序

归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的,然后再把有序子序列合并为整体有序序列[2]。

mergeSort.png

代码实现如下:

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]
 */

算法分析.PNG

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值