经典的排序算法--归并排序

归并排序核心思想:递归过程,使得前1/2和后1/2分别有序,然后对两个有序序列进行合并。从递归的逆过程看,就是两两合并,最终达到有序。
递归逆过程举例:
【3】【1】【5】【8】【7】【4】【2】【6】
【1,3】【5,8】【7,4】【2,6】
【1,3,5,8】【2,4,6,7】
【1,2,3,4,5,6,7,8】

对于归并排序来说,合并过程是算法中的核心步骤,我们不多说了,来看看代码。

import java.util.Arrays;

public class MergeSort {

    public void sort(int[] s, int low, int high) {
        if (high > low) {
            int mid = (low + high) / 2; //将数组分割成两段
            sort(s, low, mid); //对前半段进行递归排序
            sort(s, mid + 1, high); //对后半段进行递归归并排序
            merge(s, low, mid, high); //在执行完对前后两段的排序后进行归并操作
        }

    }

    public void merge(int[] s, int low, int mid, int high) {
        int[] tmp = new int[high - low + 1];//新建一个大小为high - low + 1的合并数组
        int i = low, j = mid + 1;//两个指针i和j,分别用来遍历前后半段
        int k = 0;//k为合并数组的指针
        while (i <= mid && j <= high) {
            //从i和j开始比较两段的值,取较小值放入合并数组中
            if (s[i] <= s[j]) {
                tmp[k++] = s[i++];
            } else {
                tmp[k++] = s[j++];
            }
        }
        //如果某段没有遍历完,则将剩余部分复制到合并数组中;这种情况发生在某段数值都偏大/小时
        while (i <= mid) {
            tmp[k++] = s[i++];
        }
        while (j <= high) {
            tmp[k++] = s[j++];
        }
        //然后将合并数组复制到原数组中
        for (k = 0, i = low; i <= high; i++, k++) {
            s[i] = tmp[k];
        }

    }

    public static void main(String[] args) {
        int[] s = new int[] { 3, 1, 5, 10, 7, 4, 3, 2, 1, 6 };
        MergeSort ms = new MergeSort();
        ms.sort1(s, 0, s.length - 1);
        System.out.println(Arrays.toString(s));
    }

}

归并排序的实现其实是比较好理解的,核心是维护归并过程中的归并数组,由于归并数组的存在,使得归并排序的空间复杂度为 O(n) .

归并排序在写法框架上和快速排序和类似,但是有一些本质上的区别。

  • 快速排序是在向下递归的过程中使得序列有序。每次sort开始时先执行partition使得 右>左
  • 归并排序是在递归回退时进行子序列合并,不断合并子序列,最终使序列整体有序

看到这,不知道你有没有想到很相似的过程。没错,二叉树的递归先序遍历和后序遍历,你能从快速排序和归并排序的递归写法上找到他们的影子。

猜你喜欢

转载自blog.csdn.net/tb3039450/article/details/67647627