归并排序有两种实现方式,自顶向下和自底向上。前者的思想是分治法,现将数组逐级二分再二分,分到最小的两个元素后,逐级往上归并,故其核心在于归并。后者的思想相反,采用循环的方式将小问题不断的壮大,最后变成整个大问题。
归并需要有一个同等大小的辅助数组aux,现将需要归并的元素copy至辅助数组aux中,然后通过逐一比较aux中的元素,将其放至原数组中的合适位置。
归并排序的时间复杂度为nlogn,需要额外的空间n,排序元素稳定,即使在最坏的情况下归并排序的时间复杂度也是nlogn。
1 package 排序; 2 3 import java.util.Arrays; 4 5 import edu.princeton.cs.algs4.In; 6 import edu.princeton.cs.algs4.StdOut; 7 /** 8 * @author evasean www.cnblogs.com/evasean/ 9 */ 10 @SuppressWarnings("rawtypes") 11 public class Merge归并排序 { 12 private static Comparable[] aux; 13 private static int num=1; 14 public static void merge(Comparable[] a, int lo, int mid, int hi){ 15 StdOut.println("merge lo="+lo+",mid="+mid+",hi="+hi); 16 int i = lo; //左半边元素索引记录 17 int j = mid+1; //右半边元素索引记录 18 for(int k = lo; k <= hi; k++) 19 aux[k] = a[k]; 20 for(int k = lo; k <= hi; k++){ 21 if(i > mid) a[k] = aux[j++];//左半边用尽,取右半边元素 22 else if(j > hi) a[k] = aux[i++];//右半边用尽,取左半边元素 23 else if(less(aux[j],aux[i])) a[k] = aux[j++];//右半边当前元素小于左半边当前元素,取右半边元素 24 else a[k] = aux[i++];//右半边当前元素大于或等于左半边当前元素,取左半边元素 25 } 26 StdOut.println("第"+num+"次归并结果:"+Arrays.toString(a)); 27 num++; 28 } 29 /** 30 * 自顶向下的归并排序 31 * @param a 32 */ 33 public static void sort(Comparable[] a){ 34 aux = new Comparable[a.length]; 35 sort(a,0,a.length-1); 36 } 37 public static void sort(Comparable[] a, int lo, int hi){ 38 if(hi <= lo) return; 39 int mid = lo + (hi-lo)/2; 40 sort(a,lo,mid); 41 sort(a,mid+1,hi); 42 merge(a,lo,mid,hi); 43 } 44 /** 45 * 自底向上的归并排序 46 * @param a 47 */ 48 public static void sortBU(Comparable[] a){ 49 50 int N = a.length; 51 aux = new Comparable[N]; 52 for(int sz = 1; sz < N; sz=2*sz){ 53 for(int lo = 0; lo < N - sz; lo += 2*sz){ 54 merge(a,lo,lo+sz-1,Math.min(lo+2*sz-1, N-1)); 55 } 56 } 57 } 58 59 @SuppressWarnings("unchecked") 60 private static boolean less(Comparable v, Comparable w) { 61 return v.compareTo(w) < 0; 62 } 63 64 private static void show(Comparable[] a) { 65 for (int i = 0; i < a.length; i++) 66 StdOut.print(a[i] + " "); 67 StdOut.println(); 68 } 69 70 public static boolean isSorted(Comparable[] a) { 71 for (int i = 1; i < a.length; i++) { 72 if (less(a[i], a[i - 1])) 73 return false; 74 } 75 return true; 76 } 77 78 public static void main(String[] args) { 79 String[] a = new In().readAllStrings(); 80 StdOut.println(Arrays.toString(a)); 81 sort(a); 82 assert isSorted(a); 83 show(a); 84 } 85 }