zoukankan      html  css  js  c++  java
  • 经典排序算法(五) —— Merge Sort 归并排序

    简介

    约翰·冯·诺伊曼在 1945 年提出了归并排序。归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。

    将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。

    归并排序的时间复杂度是O(nlogn)。代价是需要额外的内存空间。

    排序过程

    实现

    版本一
    @Test
    public void test() {
        int[] nums = new int[]{4, 2, 8, 9, 6, 3, 5, 7, 1, 2};
        int[] mergeSort = mergeSortSimple(nums, 0, nums.length - 1);
        printArray(mergeSort);
    }
    
    
    /*
     * 归并排序
     * @param nums 待排序数组
     * @param start 开始位置
     * @param end   结束位置
     * @return
     */
    public int[] mergeSortSimple(int[] nums, int start, int end) {
        if (start == end) {
            return new int[]{nums[start]};
        }
        int mid = (start + end) / 2;
        int[] m1 = mergeSortSimple(nums, start, mid);
        int[] m2 = mergeSortSimple(nums, mid + 1, end);
        return mergeNumsSimple(m1, m2);
    }
    
    /**
      * 合并两个有序数组
      * @param num1 待合并数组1
      * @param num2 待合并数组2
      * @return 合并数组
    */
    public int[] mergeNumsSimple(int[] num1, int[] num2) {
        int l1 = num1.length;
        int l2 = num2.length;
        int[] resNum = new int[l1 + l2];
        int resIdx = 0;
        int index1 = 0;
        int index2 = 0;
        while (resIdx < resNum.length) {
            while (index1 < l1 && index2 < l2) {
                resNum[resIdx++] = num1[index1] < num2[index2] ? num1[index1++] : num2[index2++];
            }
            while (index1 < l1) {
                resNum[resIdx++] = num1[index1++];
            }
            while (index2 < l2) {
                resNum[resIdx++] = num2[index2++];
            }
        }
        return resNum;
    }
    
    	
    /**
     * 打印数组
     * @param nums
    */
    public void printArray(int[] nums) {
        for (int num : nums) {
            System.out.print(num + "\t");
        }
        System.out.println();
    }
    
    版本二
    
     
    @Test
    public void test() {
        int[] nums = new int[]{4, 2, 8, 9, 6, 3, 5, 7, 1, 2};
        int[] res = new int[nums.length];
        mergeSortSimpleOpt(nums, 0, nums.length - 1, res);
        printArray(res);
    }
    
    
    /**
     * 归并排序
    */
    public void mergeSortSimpleOpt(int[] nums, int start, int end, int[] res) {
            if (start == end) {
                return;
            }
            int mid = (start + end) / 2;
            mergeSortSimpleOpt(nums, start, mid, res);
            mergeSortSimpleOpt(nums, mid + 1, end, res);
            mergeOpt(nums, start, end, res);
    }
    
    /**
    * 版本一递归过程中会有额外的临时数组开销,在此版本优化,直接传入定义好的结果数组做合并
    */
    public void mergeOpt(int[] nums, int start, int end, int[] res) {
        int end1 = (start + end) / 2;
        int start2 = end1 + 1;
    
        int idx1 = start;
        int idx2 = start2;
        int resIdx = idx1 + idx2 - start2;
        while (idx1 <= end1 && idx2 <= end) {
            res[resIdx++] = nums[idx1] < nums[idx2] ? nums[idx1++] : nums[idx2++];
        }
        while (idx1 <= end1) {
            res[resIdx++] = nums[idx1++];
        }
        while (idx2 <= end) {
            res[resIdx++] = nums[idx2++];
        }
        while (start <= end) {
            nums[start] = res[start++];
        }
    }
    

    复杂度

    O(nlogn)
    
  • 相关阅读:
    Fitness
    【代码优化】Unity查漏补缺
    Fitness
    MonoBehaviour生命周期与对象数据池应用
    Fitness
    点、向量、方向在局部与世界坐标系转换的对比
    在企业运营中的感触
    技术杂想2015年夏天
    Heimich manoeuvre 海姆利克氏操作
    徒手CPR心脏复苏
  • 原文地址:https://www.cnblogs.com/worldline/p/15700333.html
Copyright © 2011-2022 走看看