Java语言基础day11(归并排序)

归并排序算法思想:

归并排序(Merge Sort)就是利用归并的思想实现排序的方法。它的原理是假设初始学列有N个记录,则可以看成是N个有序的子序列,每个子序列的长度为1,然后两两归并,得到 N/2 个长度为2或1的有序子序列,再两两归并…如此重复,直至得到一个长度为N的有序序列为止,这种排序方法称为2路归并排序。

分而治之:

归并排序,该算法采用经典的分治(divide-and-conquer)策略(分治法将问题分(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之

图示:

如图所示:第一步

  1. 分解:将当前的无序序列一分为二,即求其中间点centerIndex = (startIndex + endIndex) / 2。
  2. 求解:递归地对分裂的两部分进行分裂…直到序列长度为1时停止。
  3. 合并:将分开的两个有序的数组合并为一个数组。

guibing1.png

代码实现:

private static void chaiFen(int[] arr, int startIndex, int endIndex) {
        //计算中间索引
        int centerIndex = (startIndex + endIndex) / 2;
        if (startIndex < endIndex) { //递归拆分
            //拆分左边
            chaiFen(arr, startIndex, centerIndex);
            //拆分右边
            chaiFen(arr, centerIndex + 1, endIndex);
            //归并
            mergeMethod(arr, startIndex, centerIndex, endIndex);
        }
}

合并有序的子序列:再来看看治阶段,我们需要将两个已经有序的子序列合并成一个有序序列,比如上图中的最后一次合并,要将[4,5,7,8]和[1,2,3,6]两个已经有序的子序列,合并为最终序列[1,2,3,4,5,6,7,8],来看下实现步骤。

guibing2.png
guibing3.png

代码实现

public class 归并排序 {
    public static void main(String[] args) {
        //int[] arr = {1, 3, 6, 9, 2, 4, 7, 8};
        //
        //mergeMethod(arr, 0, 3, arr.length - 1);
        //
        //System.out.println(Arrays.toString(arr));

        //上面归并测试好,下来我们给一个无序的数组,进行拆分,然后归并
        int[] arr = {1, 3, 6, 9, 2, 4, 7, 8, 10, 0, 20, 100, 89, 30, 26};
        chaiFen(arr, 0, arr.length - 1);
        System.out.println(Arrays.toString(arr));
    }

    private static void chaiFen(int[] arr, int startIndex, int endIndex) {
        //计算中间索引
        int centerIndex = (startIndex + endIndex) / 2;
        if (startIndex < endIndex) { //递归拆分
            //拆分左边
            chaiFen(arr, startIndex, centerIndex);
            //拆分右边
            chaiFen(arr, centerIndex + 1, endIndex);
            //归并
            mergeMethod(arr, startIndex, centerIndex, endIndex);
        }

    }

    /**
     * @param arr         要归并的数组
     * @param startIndex  开始索引
     * @param centerIndex 中间元素所对应的索引 不是数组长度除以2  是 (arr.length - 1)/2
     * @param endIndex    结束索引
     */
    private static void mergeMethod(int[] arr, int startIndex, int centerIndex, int endIndex) {
        //定义临时数组
        int[] tempArr = new int[endIndex - startIndex + 1];
        //定义第一个数组开始的索引
        int i = startIndex;
        //定义第二个数组开始的索引
        int j = centerIndex + 1;
        //定义临时数组的开始索引
        int index = 0;
        //遍历数组进行对比
        while (i <= centerIndex && j <= endIndex) {
            //如果第一个序列的第一个元素,小于等于第二个序列的第一个元素
            if (arr[i] <= arr[j]) {
                tempArr[index] = arr[i]; //把小的元素,放到临时数组中
                i++; //递增一下索引,下次对比第二个元素
            } else {
                tempArr[index] = arr[j];
                j++;
            }
            index++; //记得让临时数组的的索引递增
        }
        //因为两个序列的的元素个数,不是均等的,通过上面循环比较完后会有剩余元素,可能左边序列会有剩余,也可能右边元素会有剩余
        while (i <= centerIndex) {
            tempArr[index] = arr[i]; //把小的元素,放到临时数组中
            i++; //递增一下索引,下次对比第二个元素
            index++;//临时数组的的索引递增
        }
        while (j <= endIndex) {
            tempArr[index] = arr[j];
            j++;
            index++;
        }
        //这个时候,排序好的元素就会放到临时数组中
        // System.out.println(Arrays.toString(tempArr));
        //然后我们遍历临时数组,将临时数组中的元素,放置到原数组中
        for (int k = 0; k < tempArr.length; k++) {
            //注意这里k要加上起始索引
            arr[k + startIndex] = tempArr[k];
        }
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值