归并排序算法

归并排序(Merging Sort),是利用归并技术进行的排序。所谓归并,是指将两个或两个以上的有序表合并成一个新的有序表。在内部排序中,通常采用的是2-路归并排序

2-路归并排序的思想是:将一个具有 n n n 个待排序的序列看成 n n n 个长度为1有序序列,然后对相邻的子序列进行两两归并,得到 ⌈ n / 2 ⌉ \lceil n / 2 \rceil n/2 个长度为2的有序子序列,继续对相邻子序列纪念性两两归并,得到 ⌈ n / 4 ⌉ \lceil n / 4 \rceil n/4 个长度为4的有序序列,重复归并过程,直至得到一个长度为 n n n 的有序序列为止

归并排序是一种稳定的排序算法

算法步骤

  1. 需要一个与原始序列一样大小的空间,该空间用来存放合并后的序列
  2. 设定两个指针,最初位置分别为两个已经排序序列的起始位置
  3. 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动该指针到下一位置
  4. 直到某一指针超出对应序列尾部,将另一序列剩下的所有元素直接复制到合并序列的尾部

测试用例: 使用归并排序算法将数组 { 36,80,66,45,22,9,16,36 } 进行升序排序

在这里插入图片描述

归并过程

在这里插入图片描述

代码实现

    /**
     * 用于归并两个有序子序列
     * @param nums 需要排列的数组
     * @param temp 用于临时存放的数组,与nums等大小
     * @param low 低位点(相邻序列的前指针)
     * @param mid 中位点(相邻序列的后指针)
     * @param high 高位点
     * @return 返回合并后的数组
     */
    public int[] merge(int[] nums, int[] temp, int low, int mid, int high) {
        int i = low, j = mid, k = 0;
        // 循环比较大小,归并两个有序序列
        while (i < mid && j <= high){
            if (nums[i] < nums[j]) temp[k++] = nums[i++];   // 将两个有序序列比较,选取其中最小的放入temp[]临时数组中
            else temp[k++] = nums[j++];
        }
        // 循环左序列剩余的元素,并添加到temp中
        while (i < mid) temp[k++] = nums[i++];
        // 循环右序列剩余的元素,并添加到temp中
        while (j <= high) temp[k++] = nums[j++];

        // 由于temp数组是从下标0开始赋值的,而在变动的数组是nums
        // 将临时存放好的元素替换nums数组对应的元素
        for (i = 0, k = low; k <= high;){
            nums[k++] = temp[i++];
        }
        return nums;
    }

    /**
     * 归并排序
     * 将所序列中的元素对半分组之后,直至子序列中只存在1个元素时,进行两两子序列的比较再合并
     * @param nums 需要排列的数组
     * @param temp 用于临时存放的数组,与nums等大小
     * @param low 低位点
     * @param high 高位点
     * @return 返回归并好的序列
     */
    public int[] mergeSort(int[] nums, int[] temp, int low, int high) {
        if (low == high) return nums;   // 当子序列中只存在一个元素时,直接返回
        int mid = low + (high - low) / 2;     // 递归对半分组
        nums = mergeSort(nums, temp, low, mid);     // low ~ mid 区域
        nums = mergeSort(nums, temp, mid+1, high);  // mid+1 ~ high 区域
        return merge(nums, temp, low, mid + 1, high);   // low ~ high 区域
    }

时间复杂度

2-路归并排序进行第1趟排序后,有序子序列长度为2;进行第 i i i 趟排序后,有序子序列长度小于等于 2 i 2^i 2i。因此,当排序元素数量为 n n n 时,需进行 ⌈ l o g n ⌉ \lceil logn \rceil logn 趟归并。每趟归并所需时间与元素个数成正比,每次归并的时间复杂度为 O ( n ) O(n) O(n),故 2-路归并排序的时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)

由于2-路归并排序每次划分的两个子序列的长度基本一致,因此其最好、最差和平均复杂度都是 O ( n l o g n ) O(nlogn) O(nlogn)

空间复杂度
在归并排序的过程中,借助了一个与初始序列相同大小的辅助数组,因此空间复杂度为 O ( n ) O(n) O(n)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Naijia_OvO

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

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

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

打赏作者

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

抵扣说明:

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

余额充值