歸並排序有兩種實現方式,自頂向下和自底向上。前者的思想是分治法,現將數組逐級二分再二分,分到最小的兩個元素后,逐級往上歸並,故其核心在於歸並。后者的思想相反,采用循環的方式將小問題不斷的壯大,最后變成整個大問題。
歸並需要有一個同等大小的輔助數組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 }