归并排序(细~~)

一、归并

归并排序先懂归并那接下来的代码也就更加容易理解了。

假设有一个数组那我们如何进行归并呢?如下数组两边有序的数组才能进行归并

arr= {1, 4, 7, 9, 2, 5, 8}

 我们将这个数组看成两个小有序数组,但是不是分开

arrLeft = {1, 4, 7, 9}  arrRight = {2, 5, 8}

 那么我们将这两个数合并成一个有序数组

①先创建一个新数组和arr的长度一致,前期准备

        //构建一个新数组 和原来的数组长度一致
        int[] newArr = new int[arr.length];
        //将数组分为 左右两个
        int mid = arr.length / 2;

        // 左边数组下标
        int i = 0;
        //右边数组下标
        int j = mid + 1;
        //newArr 数组下标
        int k = 0;

②比较 arrLeft[i]和arrRight[j]的大小,arrLeft[i]小 则将arrLeft[i]加入新数组newArr[k]中,此时arrLeft和newArr的下标应该要指向下一个位置。arrRight[j]小 则将arrRight[j]加入新数组newArr[K]中,此时 arrRight和newArr的下标指向下一个位置.

 ③然后重复步骤②

        while (i <= mid && j < arr.length) {
            if (arr[i] <= arr[j]) {
                newArr[k] = arr[i];
                k++;
                i++;
            }else{
                newArr[k] = arr[j];
                k++;
                j++;
            }
        }

④此时我们发现arrRight先终止了循环,但是arrLeft的值还没有完全被加入到新数组中,所以我们应该在做一步操作

        while (i <= mid) newArr[k++] = arr[i++];
        while (j < arr.length) newArr[k++] = arr[j++];

这样就得到了新数组且有序 完整代码如下

    public static void merge() {
        int[] arr = {1, 4, 7, 9, 2, 5, 8};
        //构建一个新数组 和原来的数组长度一致
        int[] newArr = new int[arr.length];
        //将数组分为 左右两个
        int mid = arr.length / 2;

        // arrLeft数组下标
        int i = 0;
        // arrRight数组下标
        int j = mid + 1;
        //newArr 数组下标
        int k = 0;

        while (i <= mid && j < arr.length) {
            //arrLeft[i] 小于等于 arrRight[j]
            if (arr[i] <= arr[j]) {
                //将arrLeft[i]的值加入 新数组newArr[k] 并且 k++ i++
                newArr[k] = arr[i];
                k++;
                i++;
            }else{
                //将arrRight[j]的值加入 新数组newArr[k] 并且 k++ j++
                newArr[k] = arr[j];
                k++;
                j++;
            }
        }
        //如果某一边没有被全部加入新数组 则将其全部加入新数组
        while (i <= mid) newArr[k++] = arr[i++];
        while (j < arr.length) newArr[k++] = arr[j++];
        //打印新数组
        for (int a: newArr) {
            System.out.print(a + " ");
        }
    }

接下来将代码进行改造,改成适合所有归并的代码

    /**
     *
     * @param arr 传入数组
     * @param leftPtr 左边数组下标
     * @param rightPtr 右边数组下标 and 左边数组边界 = rightPrt-1
     * @param rightBound 右边数组边界
     */
    public static void merge(int[] arr, int leftPtr, int rightPtr, int rightBound) {

        //构建新数组
        int[] newArr = new int[rightBound - leftPtr +1];

        int mid = rightPtr -1;
        // arrLeft数组下标
        int i = leftPtr;
        // arrRight数组下标
        int j = rightPtr;
        //newArr 数组下标
        int k = 0;

        while (i <= mid && j <= rightBound) {
            newArr[k++] = arr[i] <= arr[j] ? arr[i++] : arr[j++];
        }
        //如果某一边没有被全部加入新数组 则将其全部加入新数组
        while (i <= mid) newArr[k++] = arr[i++];
        while (j <= rightBound) newArr[k++] = arr[j++];

        //将有序数组赋给以前的数组
        for(int m = 0; m < newArr.length; m++){
            arr[leftPtr + m] = newArr[m];
        }
    }

改造完大家肯定有点懵咋突然成这样了,接下来看一张图

 可以发现归并是用一次一次分解 分解到最小值 一个数组中仅仅只有一个值了之后,那么这个数组肯定是有序的,然后在一次一次合并,最后得到了有序而完整的数组。

刚刚讲了合 那么现在来讲 如何分。

很明显从中间分。

由分了之后再分,分了再分 这不就是递归嘛。所以直接上代码.

package sort;

/** 归并排序(小 ——> 大)
 * @author codelmh
 * @data 2021/11/20
 */
public class MergeSort {
    public static void main(String[] args) {
        int[] arr = {9, 2, 4, 3, 8, 5, 6};
        sort(arr,0, arr.length-1);
        for (int i =0; i < arr.length; i++){
            System.out.print(arr[i] + " ");
        }
    }
    public static void sort(int[] arr, int left, int right){
        if (left == right) return;
        //从中间分开 (left + right)/2 如果数值大将会超出int范围所以使用
        int mid = left + (right-left) / 2;
        //左边
        sort(arr, left, mid);
        //右边
        sort(arr, mid+1, right);
        //最后调用合
        merge(arr, left, mid+1, right);
    }
    /**
     *
     * @param arr 传入数组
     * @param leftPtr 左边数组下标
     * @param rightPtr 右边数组下标 and 左边数组边界 = rightPrt-1
     * @param rightBound 右边数组边界
     */
    public static void merge(int[] arr, int leftPtr, int rightPtr, int rightBound) {

        //构建新数组
        int[] newArr = new int[rightBound - leftPtr +1];

        int mid = rightPtr -1;
        // arrLeft数组下标
        int i = leftPtr;
        // arrRight数组下标
        int j = rightPtr;
        //newArr 数组下标
        int k = 0;

        while (i <= mid && j <= rightBound) {
            newArr[k++] = arr[i] <= arr[j] ? arr[i++] : arr[j++];
        }
        //如果某一边没有被全部加入新数组 则将其全部加入新数组
        while (i <= mid) newArr[k++] = arr[i++];
        while (j <= rightBound) newArr[k++] = arr[j++];

        //将有序数组赋给以前的数组
        for(int m = 0; m < newArr.length; m++){
            arr[leftPtr + m] = newArr[m];
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值