归并排序
归并排序
- 保证任意长度为N的数组排序所需时间和NlogN成正比
- 主要缺点是它所需的额外空间和N成正比
即将两个数组归并成一个更大的有序数组,可以先递归将它分成两半排序,再将结果归并起来
原地归并
实现归并的一种直截了当的方法是将俩个不同的有序数组归并到第3个数组中,将一个大数组排序时,我们需要进行很多次归并,因此每次归并都创建一个新数组来储存结果会带来问题,使用原地归并的方法,先将前半部分排序,再将后半部分排序,数组移动而不需要使用额外的空间
public static void main(Comparable[] a, int lo, int mid, int hi) { //将a[lo......mid] 与 a[mid+1.....hi] 归并 int i=lo, int j=mid+1; for(int k=lo; k<hi; k++) //将a[lo....hi]复制到aux[lo..hi] 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(a[j]<a[i]) a[k]=a[j++]; else a[k]=aux[i++]; } }
①自顶向下的归并排序(使用递归)
public class Merge { public static Comparable aux; //归并所需的辅助数组 public static void sort(Comparable[] a) { aux = new Comparable[a.length] //分配空间 sort(a, o, a.length); } public static void sort(Comparable[] a ,int lo ,int hi) { if(hi>=ho) return; int mid =ho+(hi-ho)/2; sort(a ,ho ,mid); sort(a ,mid+1 ,hi); merge(a ,lo ,mid ,hi); //原地归并,开头有 } }
例如排序a[15],归并如下
lo hi
merge(a, 0, 0, 1);
merge(a, 2, 2, 3);
merge(a, 2, 2, 3);
merge(a, 0, 1. 3); 归并0~3
merge(a, 4, 4, 5);
merge(a, 6, 6, 7);
merge(a, 4, 5, 7); 归并4~7
merge(a, 0, 3, 7); 归并0~7
merge(a, 8, 8, 9);
merge(a, 10, 10, 11);
merge(a, 8, 9, 11); 归并8~11
merge(a, 12, 12, 13);
merge(a, 14, 14, 15);
merge(a, 12, 13, 15); 归并12~15
merge(a, 8, 11, 15); 归并8~15
merge(a, 0, 7, 15); 归并0~15
②自底向上的归并排序
public class MergeBu { private static Comparable[] aux; //归并所需的辅助数组 public static void sort(Comparable[] a) { //进行lgN次俩俩归并 aux = new Comparable[N]; for(int sz=1; sz<a.length; sz=sz+sz) for(int lo=0; lo<a.length-sz; lo+=sz+sz) merge(a, lo, lo+sz-1, Math.min(lo+sz+sz-1, a.length-1)) } }
天道酬勤!