美文网首页
什么是归并排序?

什么是归并排序?

作者: 西三旗靓仔 | 来源:发表于2020-02-22 07:47 被阅读0次

    归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路[归并].

    算法描述

    • 把长度为n的输入序列分成两个长度为n/2的子序列;

    • 对这两个子序列分别采用归并排序;

    • 将两个排序好的子序列合并成一个最终的排序序列。

    归并操作

    归并操作(merge),也叫归并算法,指的是将两个顺序序列合并成一个顺序序列的方法。

    设有数列{6,202,100,301,38,8,1}

    初始状态:6,202,100,301,38,8,1

    第一次归并后:{6,202},{100,301},{8,38},{1},比较次数:3;

    第二次归并后:{6,100,202,301},{1,8,38},比较次数:4;

    第三次归并后:{1,6,8,38,100,202,301},比较次数:4;

    总的比较次数为:3+4+4=11;

    逆序数为14;

    归并操作的原理

    第一步:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列

    第二步:设定两个指针,最初位置分别为两个已经排序序列的起始位置

    第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置

    重复步骤3直到某一指针超出序列尾

    将另一序列剩下的所有元素直接复制到合并序列尾

    代码实现

    public class MergeSort {
        private static int count = 1;
        public static void main(String[] args) {
            int[] arr = {8, 4, 5, 7, 1, 3, 6, 2, 9, 10};
            int[] temp = new int[arr.length];
            split(arr, 0, arr.length - 1, temp);
            System.out.println(Arrays.toString(arr));
        }
    
        /**
         * 递归拆分数组然后合并
         *
         * @param arr   待拆分数组
         * @param left  数组左边下标
         * @param right 数组右下标
         * @param temp  用于存放合并后的有序序列的数组
         */
        public static void split(int[] arr, int left, int right, int[] temp) {
            if (left >= right) {
                return;
            }
            System.out.println("拆分第"+(count++)+"次");
            int mid = left + (right - left) / 2;
            //向左拆分
            split(arr, left, mid, temp);
            //向右拆分
            split(arr, mid + 1, right, temp);
            //每次拆分后都执行合并
            merge(arr, left, mid, right, temp);
        }
    
        /**
         * 合并两个各自有序序列(以mid为界)
         *
         * @param arr   原始数组
         * @param left  数组左边下标
         * @param mid   数组中间下标
         * @param right 数组右边下标
         * @param temp  用于存放新的有序数组
         */
        public static void merge(int[] arr, int left, int mid, int right, int[] temp) {
            int i = left;
            int j = mid + 1;
            //temp中的原始下标
            int t = 0;
    
            while (i <= mid && j <= right) {
                //两边数组都没有比较完 继续
                if (arr[i] < arr[j]) {
                    //左边数组中值更小
                    temp[t] = arr[i];
                    i++;
                } else {
                    //右边数组中值更小
                    temp[t] = arr[j];
                    j++;
                }
                t++;
            }
            //有一边已经全部复制到temp中了
            if (i <= mid) {
                //左边还没有复制完,将左边全部元素复制到temp中
                while (i <= mid) {
                    temp[t] = arr[i];
                    i++;
                    t++;
                }
            } else if (j <= right) {
                //右边还没有复制完,将右边全部元素复制到temp中
                while (j <= right) {
                    temp[t] = arr[j];
                    j++;
                    t++;
                }
            }
            //将temp复制到原arr中
            t = 0;
            while (left <= right) {
                arr[left] = temp[t];
                left++;
                t++;
            }
        }
    }
    

    复杂度

    归并排序把集合一层一层进行折半分组。如果集合长度是n,那么折半的层数就是logn,每一层进行归并操作的运算量是n。所以归并排序的时间复杂度等于每一层的运算量乘以层级数,即O(nlogn)=。
    我们再看空间复杂度,由于每次归并所创建的的额外集合都会随着方法的结束而被释放,因此这部分空间不应该累计,单次归并操作开辟的最大的空间是n,所以归并排序的空间复杂度是O(n)。


    总结

    归并排序的执行原理,主要分为以下步骤:

    1.递归的方式进行拆分,将大的数组拆分成小的数组,直到剩余一个不能拆分

    2.回溯的时候进行合并,合并时以mid为界,左右两边各自有序,通过额外的空间temp数组,将两个有序数组合并到一个有序数组中

    3.将合并后的数组复制到原数组中,当回溯完成时整个数组有序

    相关文章

      网友评论

          本文标题:什么是归并排序?

          本文链接:https://www.haomeiwen.com/subject/albkqhtx.html