zoukankan      html  css  js  c++  java
  • 排序算法之归并

    归并排序

    归并算法是在分治的思想下,将数组递归的分为两半,分别排序后,再归并成整个数组。所谓分治,即分而治之。

    优点:对于长度为 N 的数组,无论规模多大,排序所需时间总和 NlogN 成正比。
    缺点:排序所需额外空间和 N 成正比。

    注意:归并排序的核心不是交换数据。

    1. 自顶向下的归并排序

    package mysort;
    
    //归并类
    class Merge {
        //定义一个临时辅助数组
        private static Comparable[] aux;
        //对外提供排序方法
        public static void sort(Comparable[] a){
            //初始化辅助数组(注意不要减1)
            aux=new Comparable[a.length];
            sort(a,0,a.length-1);
        }
        //内部真正起到排序作用的方法
        private 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);
        }
        //归并,向上的过程
        private static void merge(Comparable[] a,int lo,int mid,int hi){
            //定义左右两边的游标
            int i=lo,j=mid+1;
            //把值全部复制过去
            for(int k=lo;k<=hi;k++){
                aux[k]=a[k];
            }
            //比较两边大小并输出回原数组
            for(int k=lo;k<=hi;k++){
                //左边输出完了,开始只取右边元素
                if(i>mid) {
                    a[k]=aux[j++];
                }
                //右边输出完了,开始只取左边元素
                else if(j>hi){
                    a[k]=aux[i++];
                }
                //比较两边,此为小者在右边的情况
                else if (less(aux[j],aux[i])){
                    a[k]=aux[j++];
                }
                //相等或较大则取左边
                else {
                    a[k]=aux[i++];
                }
            }
        }
        //此方法用于判断前者是否小于后者
        private static boolean less(Comparable m, Comparable n){
            return m.compareTo(n)<0;
        }
        //此方法用于对外提供展示方法
        public static void show(Comparable[] a){
            for(Comparable c:a){
                System.out.print(c+" ");
            }
        }
    
    }
    public class demo{
        public static void main(String[] args) {
            Integer[] a={9,5,1,1,6,5,0,8,9};
            Merge.sort(a);
            Merge.show(a);
        }
    
    }
    

    2. 自底向上的归并排序

    自顶向下的归并算法过程是将数组递归到底层,进行两两比较,再向上合并。
    而自底向上的归并排序则直接将数组元素进行比较,然后两两归并,四四归并,八八归并,直到合成一个数组。

    private static void sort(Comparable[] a){
            //sz为子数组的大小:1、2、4、8、16...
            for(int sz=1;sz<a.length;sz+=sz){
                //lo为子数组大小,可能剩下来的边角料必然小于子数组大小。
                for(int lo=0;lo<a.length-sz;lo+=2*sz){
                    //取最小是为了防止越界,因为数组长度不一定是2的幂。
                    merge(a,lo,lo+sz-1,Math.min(lo+2*sz-1,a.length-1));
                }
            }
            
    }
    

    3. 两者联系

    • 当数组长度为2的幂时,两者本质上相同,仅在访问顺序上相反。
    • 自底向上的方式较适合链表,不需要创建新节点。而自顶向下,需要创建一条新链表。
    • 自顶向下用到递归,自底向上没有用递归。
  • 相关阅读:
    归并排序处理复杂对象例子
    Java归并排序的递归与非递归实现
    Java实现一个双向链表的倒置功能
    Node<T> 的作用
    Tomcat控制台总是打印日志问题的解决办法
    git回滚部分文件到某个版本
    ios-deploy was not found
    Ionic3的http请求如何实现token验证,并且超时返回登录页
    Ionic开发遇到的坑整理
    使用gradle命令代替CUBA Studio,启动项目
  • 原文地址:https://www.cnblogs.com/juzhuxiaozhu/p/12770834.html
Copyright © 2011-2022 走看看