七大排序----SevenSort(归并排序)

本文深入讲解归并排序的原理及实现细节,包括核心的合并过程、递归拆分策略,并介绍如何通过优化提升效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

归并排序

归并排序的的核心在于merge函数(合并过程)
归并排序将排序的数组分为如下两个阶段
归而唯一:阶段一
不管三七二十一,我先把数组一分为二,直到每个数组只剩下一个元素,拆分阶段结束(此时每个子数组都是有序数组)
并而为整:阶段二
不断将相邻的两个有序子数组,合并成为一个大的有序数组,直到合并成为完整的数组,此时整个数组有序!
在这里插入图片描述
阶段二
在这里插入图片描述
归并排序的merge函数
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
归并排序的代码实现

//在数组arr[l...r]上进行归并排序
 private static void mergeSortInternal(int[] arr, int l, int r) {
        // 1.base case
        if (l >= r) {
            // 区间中只剩下一个元素或者一个元素都没有,空区间
            return;
        }
        int mid = l + ((r - l) >> 1);
        // 先在左半数组arr[l..mid]上进行归并排序
        mergeSortInternal(arr,l,mid);
        // 继续在右半数组arr[mid + 1..r]上进行归并排序
        mergeSortInternal(arr,mid + 1,r);
        // 现在开始合并左右两个有序子数组!
        merge(arr,l,mid,r);
    }
    //合并arr[l..mid] 和 arr[mid + 1..r]两个有序子数组为一个大的新的有序数组
      private static void merge(int[] arr, int l, int mid, int r) {
        // 1.先创建一个大小为两个子数组之和的临时数组aux
        int[] aux = new int[r - l + 1];
        // 2.复制两个子数组内容到aux中
        //方式一
//        for (int i = l; i <= r; i++) {
//            aux[i - l] = arr[i];
//        }
		//方式二(个人建议使用方式二,但是方式一好理解)
        // 使用System类的数组拷贝,和上面的for循环完全一致
        System.arraycopy(arr,l,aux,0,(r - l + 1));
        int i = l,j = mid + 1;
        // k表示当前覆盖到原数组的哪个下标了
        for (int k = l; k <= r; k++) {
            if (i > mid) {
                // 子数组1已经覆盖结束,直接将子数组2的剩余内容覆盖
                arr[k] = aux[j - l];
                j ++;
            }else if (j > r) {
                // 子数组2的内容已经覆盖结束,将子数组1的剩余内容覆盖
                arr[k] = aux[i - l];
                i ++;
            }else if (aux[i - l] <= aux[j - l]) {
                // 情况3.两个子数组都有元素,且子数组1元素 <= 子数组2
                arr[k] = aux[i - l];
                i ++;
            }else {
                // 情况4.两个子数组都有元素,且子数组2元素 < 子数组1
                arr[k] = aux[j - l];
                j ++;
            }
        }
    }

克隆数组方式二详解
在这里插入图片描述
归并排序的优化
代码实现

 private static void mergeSortInternal(int[] arr, int l, int r) {
        // 1.base case,碰到终止条件时,说明子数组拆分的只剩下一个元素或为空
        if (r - l <= 15) {
            // 优化2.在小数组区间上使用插入排序进行优化,减少了很多小数组的递归合并过程
            insertionSortPart(arr,l,r);
            return;
        }
        int mid = l + ((r - l) >> 1);
        // 先在左半数组arr[l..mid]上进行归并排序
        mergeSortInternal(arr,l,mid);
        // 继续在右半数组arr[mid + 1..r]上进行归并排序
        mergeSortInternal(arr,mid + 1,r);
        // 若此时arr[mid] 子数组1的最大值 <= arr[mid + 1] 子数组2的最小值 => 整个数组已经有序,压根不需要进行合并!!
        // 只有当子数组1和子数组2还有部分元素存在乱序,才需要合并!
        // 现在开始合并左右两个有序子数组!
        if (arr[mid] > arr[mid + 1]) {
            // 优化1.只有当两个子数组部分元素之间还存在乱序,才需要合并
            merge(arr,l,mid,r);
        }
    }
    //在arr[l..r]上使用插入排序
     private static void insertionSortPart(int[] arr, int l, int r) {
        // 有序区间[0..i)
        // 无序区间[i..r]
        for (int i = l + 1; i <= r; i++) {
            for (int j = i; j > l && arr[j] < arr[j - 1]; j--) {
                swap(arr,j,j - 1);
            }
        }
    }

关于归并排序的时间复杂度和空间复杂度
空间复杂度:
在这里插入图片描述
时间复杂度
在这里插入图片描述
在这里插入图片描述

时间复杂度是O(nlogn)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值