• 经典排序算法(五) —— 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)
    
  • 相关阅读:
    为什么每天都在学习,生活还是没有任何改善?
    MySql基础汇总
    BeanUtils.copyProperties(待复制对象, 待更新对象) || PropertyUtils.copyProperties(待更新对象, 待复制对象)
    ThreadLocal
    synchronized 锁
    STS报could not find tools.jar in the active JRE
    SpringBoot 定时任务 || cron表达式
    lombok注解
    cron表达式
    Thymeleaf 模板引擎
  • 原文地址:https://www.cnblogs.com/worldline/p/15700333.html
Copyright © 2020-2023  润新知