归并排序理解(Java)

归并排序

1、原理

归并排序是一种概念上最简单的排序算法,与快速排序一样,归并排序也是基于分治法的。 **归并排序将待排序的元素序列分成两个长度相等的子序列,为每一个子序列排序,然后再将他们合并成一个子序列。**合并两个子序列的过程也就是两路归并。

2、复杂度

归并排序是一种稳定的排序算法,归并排序的主要问题在于它需要一个与待排序数组一样大的辅助数组空间。由于归并排序每次划分时两个子序列的长度基本一样,所以归并排序最好、最差和平均时间复杂度都是nlog2n

我们可以通过下图非常容易看懂归并排序的过程:

这里写图片描述

将两个排好序的子序列合并为一个子序列的方法:每次都是从未比较的两个子序列的最小值中选出一个更小值。

3、java代码
  • 形参有辅助数组时
    /**
     * 递归进行归并排序
     *
     * @param nums  待排序数组序列
     * @param start 排序序列起始位
     * @param end   排序序列终止位
     * @param temp  辅助数组 存在中间排序结果,长度需于原数组相同
     */
    public void mergeSort(int nums[], int start, int end, int temp[]) {
        if (start >= end) return;//当前序列只有一个元素时结束递归
        int middle = (start + end) / 2;//划分子序列的边界
        mergeSort(nums, start, middle, temp);//对左侧子序列进行递归归并排序
        mergeSort(nums, middle + 1, end, temp);//对右侧子序列进行递归归并排序
        merge(nums, start, middle, end, temp);//合并两个子序列 这两个子序列一定为有序(序列中只有一个元素时当成有序)
    }

    /**
     * 两路归并算法 ,将两个排好序的子序列合并为一个子序列
     *
     * @param nums   待排序数组序列
     * @param start  左侧序列的起点
     * @param middle 左侧序列的终点
     * @param end    右侧序列的终点 右侧序列的起点默认为 middle+1
     * @param temp   辅助数组 存在中间排序结果,长度需于原数组相同
     */
    public void merge(int[] nums, int start, int middle, int end, int temp[]) {
        //辅助数组的存放指针
        int flag = start;
        //左侧序列的检测指针
        int start1 = start;
        //右侧序列的检测指针
        int start2 = middle + 1;

        //将两个序列依据最小值不断合并直至一个序列中的合并完
        while (start1 <= middle && start2 <= end) {
            if (nums[start1] < nums[start2]) {
                temp[flag] = nums[start1];
                start1++;
            } else {
                temp[flag] = nums[start2];
                start2++;
            }
            flag++;
        }
        //如果左侧序列未合并完,将剩余的数直接加到合并序列尾部
        while (start1 <= middle) {
            temp[flag] = nums[start1];
            start1++;
            flag++;
        }
        //同上
        while (start2 <= end) {
            temp[flag] = nums[start2];
            start2++;
            flag++;
        }
        //复制合并完的序列到原数组
        for (int i = start; i <= end; i++) {
            nums[i] = temp[i];
        }
    }
  • 形参无辅助数组时,合并时构建相应大小的辅助数组即可。
   public void mergeSort(int nums[], int start, int end) {
        if (start >= end) return;//当前序列只有一个元素时结束递归
        int middle = (start + end) / 2;//划分子序列的边界
        mergeSort(nums, start, middle);//对左侧子序列进行递归归并排序
        mergeSort(nums, middle + 1, end);//对右侧子序列进行递归归并排序
        merge(nums, start, middle, end);//合并两个子序列
    }

    public void merge(int[] nums, int start, int middle, int end) {
        int[] temp = new int[end - start + 1];
        int flag = 0;
        int start1 = start;
        int start2 = middle + 1;
        while (start1 <= middle && start2 <= end) {
            if (nums[start1] < nums[start2]) {
                temp[flag] = nums[start1];
                start1++;
            } else {
                temp[flag] = nums[start2];
                start2++;
            }
            flag++;
        }
        while (start1 <= middle) {
            temp[flag] = nums[start1];
            start1++;
            flag++;
        }
        while (start2 <= end) {
            temp[flag] = nums[start2];
            start2++;
            flag++;
        }
        for(int i = 0;i<=temp.length;i++){
            nums[i+start]=temp[i];
        }
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值