算法_归并排序
归并排序的基本思想是:将两个已经有序的数组,归并成为更大的有序数组.这种操作称为归并排序.要让一个数组排序,可以先递归的把它分成两半分别排序,然后将结果归并起来.归并排序能够保证对一个任意长度为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次.
加油