zoukankan      html  css  js  c++  java
  • 排序:归并排序

    简介

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

    排序原理:

    1.尽可能的一组数据拆分成两个元素相等的子组,并对每一个子组继续拆分,直到拆分后的每个子组的元素个数是1为止。

    2.将相邻的两个子组进行合并成一个有序的大组;

    3.不断的重复步骤2,直到最终只有一个组为止。

    image-20210805152636086

    自顶而下的归并排序代码实现:

    /**
     * @author wen.jie
     * @date 2021/8/5 15:46
     */
    public abstract class AbstractSort {
    
        /**
         * 比较
         * @author wen.jie
         * @date 2021/8/4 17:18
         */
        protected static boolean greater(Comparable v, Comparable w) {
            return v.compareTo(w) > 0;
        }
    
        /**
         * v是否比w小
         * @author wen.jie
         * @date 2021/8/5 15:59
         */
        protected static boolean less(Comparable v, Comparable w){
            return greater(w, v);
        }
    
        /**
         * 交换
         * @author wen.jie
         * @date 2021/8/4 17:27
         */
        protected static void exchange(Comparable[] a, int i, int j) {
            Comparable temp = a[i];
            a[i] = a[j];
            a[j] = temp;
        }
    }
    
    /**
     * @author wen.jie
     * @date 2021/8/5 16:13
     */
    public class Merge extends AbstractSort{
    
        private static Comparable[] assist;
    
        public static void sort(Comparable[] a){
            assist = new Comparable[a.length];
            sort(a, 0, a.length - 1);
        }
    
        /**
         * 排序:从lo到hi的元素
         * @author wen.jie
         * @date 2021/8/5 16:17
         */
        public static void sort(Comparable[] a, int lo, int hi){
            if(hi <= lo) return;
            int mid  = lo + (hi - lo) / 2;
            //两组分别排序
            sort(a, lo, mid);
            sort(a, mid + 1, hi);
            //两组中的数据进行合并
            merge(a, lo, mid, hi);
        }
    
        /**
         * 合并两个分组
         * @author wen.jie
         * @date 2021/8/5 16:21
         */
        public static void merge(Comparable[] a, int lo, int mid, int hi){
            //定义两个指针,对应着两个子数组
            int i = lo, j = mid + 1;
            //将所有元素先复制到临时数组中
            System.arraycopy(a, lo, assist, lo, hi + 1 - lo);
            //归并到a[lo...hi]
            for (int k = lo; k <= hi; k++) {
                if(i > mid)
                    //左半边用尽,取右半边元素
                    a[k] = assist[j++];
                else if (j > hi)
                    //右半边用尽,取右半边元素
                    a[k] = assist[i++];
                else if (less(assist[j], assist[i]))
                    //右边比左边小,取右边元素
                    a[k] = assist[j++];
                else
                    //左边比右边小,取左边元素
                    a[k] = assist[i++];
            }
        }
    
    }
    

    自底而上的归并排序:

    这里是先归并微型数组,再成对归并得到的子数组,如此这般,直到我们将整个数组归并到一起。

    //只有sort方法不一样,其他方法一模一样    
    public static void sort(Comparable[] a){
            int n = a.length;
            assist = new Comparable[n];
            for (int sz = 1; sz < n; sz = 2*sz) {
                for (int lo = 0; lo < n-sz; lo += 2*sz){
                    merge(a, lo, lo+sz-1, Math.min(lo+sz+sz-1, n-1));
                }
            }
        }
    

    自顶而下时间复杂度分析

    image-20210805174403054

    用树状图来描述归并,如果一个数组有8个元素,那么它将每次除以2找最小的子数组,共拆log8次,值为3,所以 树共有3层,那么自顶向下第k层有2^k个子数组,每个数组的长度为2^(3-k),归并最多需要2^(3-k)次比较。因此每层 的比较次数为 2^k * 2^(3-k)=2^3,那么3层总共为 3*2^3。

    假设元素的个数为n,那么使用归并排序拆分的次数为log2(n),所以共log2(n)层,那么使用log2(n)替换上面3*2^3中 的3这个层数,最终得出的归并排序的时间复杂度为:log2(n)* 2^(log2(n))=log2(n)*n,根据大O推导法则,忽略底数,最终归并排序的时间复杂度为O(nlogn);

  • 相关阅读:
    std thread
    windows更新包发布地址
    How to set up logging level for Spark application in IntelliJ IDEA?
    spark 错误 How to set heap size in spark within the Eclipse environment?
    hadoop 常用命令
    windows 安装hadoop 3.2.1
    windows JAVA_HOME 路径有空格,执行软连接
    day01MyBatisPlus条件构造器(04)
    day01MyBatisPlus的CRUD 接口(03)
    day01MyBatisPlus入门(02)
  • 原文地址:https://www.cnblogs.com/wwjj4811/p/15104541.html
Copyright © 2011-2022 走看看