【高级排序】之归并排序

算法评价

  • 时间复杂度

  • 空间复杂度

  • 稳定性:稳定。

  • 适用数据规模量:大规模。

算法复杂度与数据规模量关系图

算法说明

        如下图所示,先将待排序数组进行拆分(拆分规则多样,下图为二分法),然后再将拆分开的各个子元素进行归并(归并方式多样,下图为两路归并),得到多个小的有序的数组集合,然后再将各个有序的小数组集合归并……最终得到有序数组集合。

算法演示图

注:此动图中采用前序遍历的方式进行归并。

Java对归并排序的实现

/**
 * 归并排序的Java实现
 *
 * @author JustryDeng
 * @date 2019/5/6 18:38
 */
public class Merge {

    /**
     * 归并排序的java实现
     *
     * @param originArray
     *            要被排序的元素集合
     * @param asc
     *            升序/降序。 true-升序; false-降序
     *
     * @date 2019/5/6 18:40
     */
    public static void sort(int[] originArray, boolean asc) {
        if (originArray == null || originArray.length <= 1) {
            return;
        }
        // 数组最左边元素的索引
        int left = 0;
        // 数组最右边元素的索引
        int right = originArray.length - 1;
        splitAndMerge(originArray, left, right, asc);
    }


    /**
     * (两路)拆分、归并 数组
     *
     * @param originArray
     *            数组
     * @param left
     *            数组的起始元素索引
     * @param right
     *            数组的结尾元素索引
     * @param asc
     *            升序/降序。 true-升序; false-降序
     * @date 2019/5/8 23:06
     */
    private static void splitAndMerge(int[] originArray, int left, int right, boolean asc) {
        // 中间那个数的索引
        int center = (left + right) / 2;
        /*
         * 当目标区域要只有一个元素时,不再进行拆分
         *
         * 已知originArray长度大于0, 这里简单数学证明: 当center = right时,originArray长度为1
         * ∵ center = (left + right) / 2 且 center = right
         * ∴ right = (left + right) / 2
         * ∴ 2 * right = left + right
         * ∴ right = left
         * ∴ right = left
         * ∴ originArray长度为1
         */
        if (center == right) {
            return;
        }
        // 二叉树【前序遍历】, 再次进行拆分
        splitAndMerge(originArray, left, center, asc);
        splitAndMerge(originArray, center + 1, right, asc);
        // 合并
        merge(originArray, left, center, right, asc);
    }

    /**
     * 归并两个有序的数组
     *
     * @param originArray
     *            数组。 注:该数组由两个紧邻的 有序数组组成
     * @param left
     *            要归并的第一个数组的起始元素索引
     * @param center
     *            要归并的第一个数组的结尾元素索引
     * @param right
     *            要归并的第二个数组的结尾元素索引
     *            注:要合并的第二个数组的结尾元素索引为center + 1
     * @param asc
     *            升序/降序。 true-升序; false-降序
     * @date 2019/5/8 23:06
     */
    private static void merge(int[] originArray, int left, int center, int right, boolean asc) {
        int[] tmpArray = new int[right - left + 1];
        int i = left, j = center + 1, tmpIndex = 0;
        // 循环比较, 直至其中一个数组所有元素 拷贝至 tmpArray
        while (i <= center && j <= right) {
            // 控制升序降序
            boolean ascFlag = asc ? originArray[i] <= originArray[j] : originArray[i] >= originArray[j];
            if (ascFlag) {
                tmpArray[tmpIndex] = originArray[i];
                i++;
                tmpIndex++;
            } else {
                tmpArray[tmpIndex] = originArray[j];
                j++;
                tmpIndex++;
            }
        }
        // 将剩余那个没拷贝完的数组中剩余的元素 拷贝至 tmpArray
        while (i <= center) {
            tmpArray[tmpIndex] = originArray[i];
            i++;
            tmpIndex++;
        }
        while (j <= right) {
            tmpArray[tmpIndex] = originArray[j];
            j++;
            tmpIndex++;
        }
        // 将临时数组中的元素按顺序拷贝至originArray
        System.arraycopy(tmpArray, 0, originArray, left, tmpArray.length);
    }

}

测试一下

控制台输出:

归并排序,学习完毕!

 

^_^ 如有不当之处,欢迎指正

^_^ 本文已被收录进《程序员成长笔记(五)》,笔者JustryDeng

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值