基本思想:
歸並排序是將兩個或兩個以上的有序表組合成一個新的有序表。其基本思想是:先將N個數據看成N個長度為1的表,將相鄰兩個表合並,得到長度為2的N/2個有序表,進一步將相鄰的表合並,得到長度為4的N/4個有序表,以此類推,知道所有數據合並成一個長度為N的有序表位置。沒一次歸並稱為一趟。
要解決歸並問題,首先要解決兩兩歸並問題(兩個有序表合並成一個有序表),其java實現為:
1 2 public static void mergeTwo(int[] data,int first,int mid,int last,int[] tmp){ 3 4 //把data[first]-data[mid]當做第一個有序序列 ,這里設為A 5 //把data[mid+1]-data[last]當做第二個有序序列,這里設為B 6 //將兩個有序序列合並,形成的新序列為data[first]-data[last] 7 int i = first, j = mid + 1; 8 int m = mid, n = last; 9 int k = 0; 10 while(i<=m&&j<=n){ 11 //A序列和B序列依次從起始值開始比較 12 //如果A序列值小,就將其移值tmp中 13 //並且A下標i+1;tmp下標k+1 14 if(data[i]<data[j]){ 15 tmp[k++] =data[i++]; 16 }else{ 17 //如果B序列值小,就將其移值tmp中 18 //並且B下標i+1;tmp下標k+1 19 tmp[k++] = data[j++]; 20 } 21 } 22 23 //如果A序列或者B序列已經全部移到tmp中 24 //則剩余的另一個序列依次移到tmp中 25 while(i<=m){ 26 tmp[k++] =data[i++]; 27 } 28 while(j<=n){ 29 tmp[k++] = data[j++]; 30 } 31 32 //遍歷tmp,將tmp中元素移會data,此時data[first]-data[last]為有序序列 33 for (i = 0; i < k; i++) { 34 data[first + i] = tmp[i]; 35 } 36 }
實現方法:
歸並排序有兩種實現方法:
1)自底向上
2)自頂向下
自底向上的基本思想是:第一趟歸並排序時,將待排序的文件R[1.....n]看做是n個長度為1的有序文件,將這些子文件兩兩歸並,若n為偶數,則得到n/2個長度為2的有序文件;若n為奇數,則最后一個子文件輪空(不參與歸並,直接進入下一趟歸並),估本趟歸並完成后,前n/2-1個有序子文件長度為2,單最后一個子文件長度仍未1;第二趟歸並則是將第一趟歸並所得到的n/2個有序文件兩兩歸並,如此反復,知道得到最后長度為n的有序文件位置。
其程序實現:
1 package sortDemo; 2 3 public class MargeSort { 4 5 public static void main(String[] args) { 6 int[] sort ={3,2,1,4,6,5,8,9,10,7} ; 7 System.out.println("排序前:"); 8 print(sort); 9 int[] tmp = new int[sort.length]; 10 mergeSort(sort,0,sort.length-1,tmp); 11 System.out.println("\n排序后:"); 12 print(sort); 13 } 14 15 public static void mergeSort(int[] data,int first,int last,int[] tmp){ 16 if(first<last){ 17 int mid = (last-first)/2+first; 18 //使左側有序 19 mergeSort(data,first,mid,tmp); 20 //使右側有序 21 mergeSort(data,mid+1,last,tmp); 22 //合並兩個有序的子序列 23 mergeTwo(data, first, mid, last, tmp); 24 } 25 } 26 27 public static void mergeTwo(int[] data,int first,int mid,int last,int[] tmp){ 28 29 //把data[first]-data[mid]當做第一個有序序列 ,這里設為A 30 //把data[mid+1]-data[last]當做第二個有序序列,這里設為B 31 //將兩個有序序列合並,形成的新序列為data[first]-data[last] 32 int i = first, j = mid + 1; 33 int m = mid, n = last; 34 int k = 0; 35 while(i<=m&&j<=n){ 36 //A序列和B序列依次從起始值開始比較 37 //如果A序列值小,就將其移值tmp中 38 //並且A下標i+1;tmp下標k+1 39 if(data[i]<data[j]){ 40 tmp[k++] =data[i++]; 41 }else{ 42 //如果B序列值小,就將其移值tmp中 43 //並且B下標i+1;tmp下標k+1 44 tmp[k++] = data[j++]; 45 } 46 } 47 48 //如果A序列或者B序列已經全部移到tmp中 49 //則剩余的另一個序列依次移到tmp中 50 while(i<=m){ 51 tmp[k++] =data[i++]; 52 } 53 while(j<=n){ 54 tmp[k++] = data[j++]; 55 } 56 57 //遍歷tmp,將tmp中元素移會data,此時data[first]-data[last]為有序序列 58 for (i = 0; i < k; i++) { 59 data[first + i] = tmp[i]; 60 } 61 } 62 63 public static void print(int[] a){ 64 for (int i = 0; i < a.length; i++) { 65 System.out.print(a[i]+" "); 66 } 67 System.out.println(); 68 } 69 }
算法分析:
(1)穩定性
歸並排序是一種穩定的排序。
(2)存儲結構要求
可用順序存儲結構,也易於在鏈表上實現。
(3) 時間復雜度
對長度為n的文件,需要進行[log2n]趟二路歸並,沒趟歸並的時間為O(n),故其時間復雜度無論是在最好情況下還是最壞情況下均是O(nlgn).