經典排序算法--歸並排序


基本思想:

  歸並排序是將兩個或兩個以上的有序表組合成一個新的有序表。其基本思想是:先將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).

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM