算法-9-归并排序

九、归并排序(Merge Sort)

1、概念

使用归并思想,将排序序列进行分-合的操作,实现最终的排序。

分-合(devide-conquer):将问题为一些小问题,递归(也可以采用迭代的方式)拆分子序列(完全二叉树),各个求解,再将得到的各个答案,并在一起。

        34158276
   3415          8276
 34    15      82    76
3  4  1  5    8  2  7  6
 34    15      28    67
   1534          2867
        12345678

递归方式:准备一个和原排序序列长度一样的,临时辅助排序序列,找到中间索引比较两端元素值大小小的放到临时排序序列前面大的放到临时排序序列后面(正序),最后再将临时排序中的元素值,依次覆盖掉本次排序比较序列的元素值。

2、过程

  1. 创建一个临时排序序列,长度等于待排序序列的长度
  2. 分的方法:每次都找到中间索引值,并递归调用分的方法,起始索引到中间索引,中间索引+1到终止索引,最后调用合的方法
  3. 合的方法左端比较索引起始索引开始,右端比较索引中间索引的下一位开始,当左端比较索引和右端比较索引,均未到达中间索引和终止索引时,比较中间索引值两端的元素值大小,将较小的元素值赋值给临时排序数组,并右移左端比较索引和右端比较索引,再将未比较完的左端元素值或右端赋值给临时排序数组。最后再将临时排序数组的元素,依次覆盖掉本次比较排序序列的部分元素值(从起始索引到终止索引)。

3、示例

正序

public void mergeSort(int[] array) {
    int len = array.length;
    int[] temp = new int[len];
    mergeSort(array, 0, len - 1, temp);
}

private void mergeSort(int[] array, final int begin, final int end, int[] temp) {
    if (begin < end) {
        int middle = (begin + end) >> 1;
        mergeSort(array, begin, middle, temp);
        mergeSort(array, middle + 1, end, temp);
        merge(array, begin, middle, end, temp);
    }
}

private void merge(int[] array, final int begin, final int middle, final int end, int[] temp) {
    int b = begin;
    int m = middle + 1;
    int index = 0;
    while (b <= middle && m <= end) { // 起始-中间,中间+1-终止
        if (array[b] <= array[m]) { // 比较两端大小
            temp[index] = array[b];
            index++;
            b++;
        } else {
            temp[index] = array[m];
            index++;
            m++;
        }
    }

    while (b <= middle) { // 将左端剩余部分添加到临时数组中
        temp[index] = array[b];
        index++;
        b++;
    }
    while (m <= end) { // 将右端剩余部分添加到临时数组中
        temp[index] = array[m];
        index++;
        m++;
    }

    b = begin;
    index = 0;
    while (b <= end) { // 重新赋值:将临时数组中的元素赋值给原始数组
        array[b] = temp[index];
        b++;
        index++;
    }
}

倒序

public void mergeSort(int[] array) {
    int len = array.length;
    int[] temp = new int[len];
    mergeSort(array, 0, len - 1, temp);
}

private void mergeSort(int[] array, final int begin, final int end, int[] temp) {
    if (begin < end) {
        int middle = (begin + end) >> 1;
        mergeSort(array, begin, middle, temp);
        mergeSort(array, middle + 1, end, temp);
        merge(array, begin, middle, end, temp);
    }
}

private void merge(int[] array, final int begin, final int middle, final int end, int[] temp) {
    int b = begin;
    int m = middle + 1;
    int index = 0;
    while (b <= middle && m <= end) {
        if (array[b] >= array[m]) { // 倒序
            temp[index++] = array[b++];
        } else {
            temp[index++] = array[m++];
        }
    }

    while (b <= middle || m <= end) {
        if (b <= middle) {
            temp[index++] = array[b++];
        } else {
            temp[index++] = array[m++];
        }
    }

    b = begin;
    index = 0;
    while (b <= end) {
        array[b++] = temp[index++];
    }
}

4、性能

  • 时间复杂度:平均时间复杂度O(nlog₂n),最坏时间复杂度O(nlog₂n)
  • 空间复杂度:O(nlog₂n) 因为尾递归
  • 稳定性:不稳定(a=b,排序前a在b的前面,排序后a不一定还在b的前面)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值