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

      归并排序的基本思想是:将两个已经有序的数组,归并成为更大的有序数组.这种操作称为归并排序.要让一个数组排序,可以先递归的把它分成两半分别排序,然后将结果归并起来.归并排序能够保证对一个任意长度为N的数组排序所需时间和NlogN成正比.

      基本的归并方法代码如下:该方法先将所有的元素复制到aux[]中,然后再归并到a[]中.方法在归并的时候,进行了四次条件判断:左半边用尽(取右半边的元素),右半边用尽(取左半边的元素),右半边的当前元素小于左半边的当前元素(取右半边的元素)以及右半边的元素大于等于左半边的当前元素.

    private static void merge(Comparable[] a, int lo, int mid, int hi) {
            int i=lo;
            int 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>lo) a[k]=aux[i++];
                else if(less(aux[i],aux[j])) a[k]=aux[i++];
                else a[k]=aux[j++];
            }
        }

      利用上面的归并代码,可以产生两种排序方法,自顶向下和自底向上的排序算法,分别整理如下:

      自顶向下的算法认为:如果能够将两个子数组排序,就能够通过归并两个子数组来将整个数组进行排序:

    public class Merge {
        private static Comparable[] aux;
        public static void sort(Comparable[] a) {
            aux=new Comparable[a.length];
            sort(a,0,a.length-1);
        }
        public static void sort(Comparable[] a, int lo, int hi) {
            if(hi<=lo) return;
            int mid=lo+(hi-lo)/2;
            sort(a,lo,mid);            //左半边排序[[9
            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;
            int 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>lo) a[k]=aux[i++];
                else if(less(aux[i],aux[j])) a[k]=aux[i++];
                else a[k]=aux[j++];
            }
        }
        public static boolean less(Comparable v, Comparable w) {
            return v.compareTo(w)<0;
        }
    }

      自顶向下的归并排序对于长度为N的任意数组,需要1/2NlgN~NlgN次比较.(证明方法见算法第四版).此外归并排序还有可以优化的地方,如对于小规模的数组可以使用插入排序,可以添加判断条件,例如通过测试a[mid]小于等于a[mid+1],我们就认为数组已经是有序的并跳过merge方法.

      自底向上的归并排序利用先归并那些微型数组,然后再成对归并得到的子数组,如此这般,直到我们将整个数组归并在一起.自底向上的归并排序算法的实现如下:

    public class MergeBU {
        private static Comparable[] aux;
        
        public static void sort(Comparable[] a) {
            int N=a.length;
            aux=new Comparable[N];
            for(int sz=1;sz<N;sz=sz+sz) /*子数组的大小*/{
                for(int lo=0;lo<N-sz;lo+=sz+sz) /*lo:子数组的索引*/{
                    merge(a,lo,lo+sz-1,Math.min(lo+sz+sz-1, N));
                }
            }
        }
        public static boolean less(Comparable v, Comparable w) {
            return v.compareTo(w)<0;
        }
        public static void merge(Comparable[] a,int lo,int mid,int hi) {
            int i=lo;
            int 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>lo) a[k]=aux[i++];
                else if(less(aux[i],aux[j])) a[k]=aux[i++];
                else a[k]=aux[j++];
            }
        }
    }

      对于任意的长度为N的任意数组,自底向上的归并排序需要1/2NlgN至NlgN次比较.最多访问数组6NlgN次.

  • 相关阅读:
    sql 笔记之一
    js的Location
    VS无法使用.XXXX附加到程序
    C#遍历对象的方法
    解决tomcat启动时中文乱码问题。
    动态sql foreach 循环报错问题
    java跳过https证书直接请求工具类
    安装svn报2503错误处理方法
    oracle常用的一些查询命令
    Oracle11g安装过程中忘记进行口令配置
  • 原文地址:https://www.cnblogs.com/hlhdidi/p/5638972.html
Copyright © 2011-2022 走看看