算法基础:归并排序

778 阅读3分钟

我正在参加「掘金·启航计划」

上一篇文章介绍了什么是分治思想,今天就来看一下它其中一个继承人-- 归并排序,本章主要介绍归并排序的原理,以及对一个实际问题进行编码。

学习的内容


1. 什么是归并排序

比如我们拿到一个数组,如果想使用归并排序,应该怎么做呢?首先我们将数组从中间切分,分成左右两个部分,然后对左半部分和右半部分进行排序,两边部分又可以继续拆分,直至子数组中只剩下一个数据位置。

然后就要将拆分的子数组进行合并,合并的时候会涉及到两个数据进行比较,然后按照大小进行排序,以此往上进行合并。

拆分过程

image.png 合并过程

image.png

从上面我们可以看出,我们最终将大的数组拆分成只有单个数据的数组,然后进行合并,在合并过程中比较两个长度为1的数组,进行排序合并成新的子数组,然后依次类推,直至全部排序完成,也就意味着原数组排序完成。

2.代码示例


public class Solution {
    
    public static void main(String[] args) {
        sortArray(new int[]{3,2,5,42,11});
    }
    public static int[] sortArray(int[] nums) {
        int len = nums.length;
        int[] temp = new int[len];
        mergeSort(nums, 0, len - 1, temp);
        return nums;
    }

    /**
     * 对数组 nums 的子区间 [left, right] 进行归并排序
     *
     * @param nums
     * @param left 左侧下标
     * @param right 右侧下标
     * @param temp  用于合并两个有序数组的辅助数组,全局使用一份,避免多次创建和销毁
     */
    private static void mergeSort(int[] nums, int left, int right, int[] temp) {
        // 1.基准条件,递归结束
        if(left >= right){
            return;
        }

        int mid = left + (right - left) / 2;
        //左侧子数组拆分阶段
        mergeSort(nums, left, mid, temp);
        //右侧子数组拆分阶段
        mergeSort(nums, mid + 1, right, temp);

        //合并阶段
        merge(nums, left, mid, right, temp);
    }


    /**
     * 合并数组,此时左侧数组为有序、右侧数组也是有序
     * 需要将两个子数组进行排序合并
     *
     * @param mid   [left, mid] 有序,[mid + 1, right] 有序
     */
    private static void merge(int[] nums, int left, int mid, int right, int[] temp) {
        System.arraycopy(nums, left, temp, left, right + 1 - left);

        int i = left;
        int j = mid + 1;

        for (int k = left; k <= right; k++) {
            if (i == mid + 1) {
                nums[k] = temp[j];
                j++;
            } else if (j == right + 1) {
                nums[k] = temp[i];
                i++;
            } else if (temp[i] <= temp[j]) {
                nums[k] = temp[i];
                i++;
            } else {
                nums[k] = temp[j];
                j++;
            }
        }
    }
}
​
  • 时间复杂度:O(NlogN),N 为数组的长度
  • 空间复杂度:O(N),因为使用了辅助数组

总结

本章简单分析了归并排序的原理以及分享了一个实际案例,无论是归并还是归并算法,对理解递归还是很有帮助的,之前总是靠着想递归流程,复杂点的绕着绕着就晕了,后面会再看一下快速排序,他和本文提到的归并排序都是分治思想,等说完快排,再一起对比两者的区别。