归并排序

归并排序

所谓归并排序,意思就是合并两个已经有序的列表,然后输出到结果列表。这一点从字面意思也能大概看来。下面我们从两个点说归并排序:

  1. 归并排序的归并怎么归?
  2. 归并排序需要两个已经排序的数组,这两个数组从何处来?

归并排序的归并怎么归

假设有两个已经排序的数组A和B以及一个空数组C,那么归并排序的归并过程大致如下所示:

假设有两个指针Apos和Bpos分别指向数组A和数组B的第一个位置,C指向数组C的第一个位置。

第一步,比较Apos和Bpos位置的值,将最小的放到C,并且Cpos自增1指向下一个空位。在我们的例子中,21比8大,所以将8放到C的第一位,Cpos自增1,指向第二个元素,并且Bpos也得自增1,指向数组B的下一个元素。最后直到将数组A 或数组B中剩余的元素直接拷贝到数组C,归并完成。
归并排序合并过程

归并排序需要两个已经排序的数组,这两个数组从何处来

分而治之
归并排序基于分而治之的思想,利用了递归的实现方式。这两个数组自然是从给定原始数组中来,如上图所示,给定一个8个元素的数组,首先将他分为两个数组,每个数组包含4个元素,在将这两个数组分成4个数组,每个数组包含2个元素,最后将这4个数组分成8个数组,每个数组包含一个元素,这个时候每个数组剩下一个元素,自然而然已经是排序的了(这就是我们的递归终止条件)。到了这一步以后,在进行治的过程,这个过程结合上面两张图可以很清楚的看明白了。好了到这里该抄一抄书上的代码了。

代码

    /**
     * 归并两个数组到一个数组,分而治之的治
     *
     * @param arr 原始数组
     * @param tmpArr 存放合并结果的数组
     * @param leftPos 子数组最左边的索引
     * @param rightPos 第二部分数组的开始位置
     * @param rightEnd
     */
    private static void merge(int[] arr, int[] tmpArr, int leftPos, int rightPos, int rightEnd) {
        int leftEnd = rightPos - 1;
        int tmpPos = leftPos;
        int numElements = rightEnd - leftPos + 1;
        while (leftPos <= leftEnd && rightPos <= rightEnd) {
            if (arr[leftPos] <= arr[rightPos]) {
                tmpArr[tmpPos++] = arr[leftPos++];
            } else {
                tmpArr[tmpPos++] = arr[rightPos++];
            }
        }
        // 拷贝左边数组的剩余元素到临时数组
        while (leftPos <= leftEnd) {
            tmpArr[tmpPos++] = arr[leftPos++];
        }
        // 拷贝右边数组的剩余元素到临时数组
        while (rightPos <= rightEnd) {
            tmpArr[tmpPos++] = arr[rightPos++];
        }
        // 拷贝临时数组的元素到给定数组,实现排序
        for (int i = 0; i < numElements; i++, rightEnd--) {
            arr[rightEnd] = tmpArr[rightEnd];
        }
    }

    /**
     * 归并排序,分而治之的分
     *
     * @param arr 原始数组
     * @param tmpArr 存放合并结果的临时数组
     * @param left 最左边索引
     * @param right 最右边索引
     */
    private static void mergeSort(int[] arr, int[] tmpArr, int left, int right) {
        if (left < right) {
            int center = (left + right) / 2;
            mergeSort(arr, tmpArr, left, center);
            mergeSort(arr, tmpArr, center + 1, right);
            merge(arr, tmpArr, left, center + 1, right);
        }
    }

    public static void mergeSort(int[] arr) {
        int[] tmpArr = new int[arr.length];
        mergeSort(arr, tmpArr, 0, arr.length - 1);
    }

时间复杂度

归并排序的时间复杂度最好、最差、平均都是O(nlog2n)。且是一种稳定的排序方式

git地址

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

半__夏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值