歸並排序是一種借助”歸並“進行排序的方法。
歸並的含義是將兩個或兩個以上的有序序列歸並為一個有序序列的過程。歸並排序的主要思想是:將若干有序序列逐步歸並,最終歸並為一個有序序列。
其中最常見的是二路歸並排序。
二路歸並排序是一種穩定的排序方法,其基本思想是:將若干個有序序列兩兩歸並,直到形成一個有序序列為止。
方法如下:將一個長度為n的無序序列看作是n個長度為1的有序序列的集合。然后兩兩歸並,直到整個序列有序。
在歸並的過程中,可能會破壞原序列的有序性,所以需要一個新的數組在存儲歸並后的結果。
一次歸並的算法是從開始同時遍歷兩個序列,將較小的值放入結果序列中,直到遍歷結束,成為一個有序序列。
代碼如下:
1 void Merge(int r[],int r1[],int s,int m,int t) 2 { 3 int i=s,j=m+1,k=s; 4 while(i<=m&&j<=t) 5 { 6 if(r[i]<=r[j]) 7 { 8 r1[k]=r[i]; 9 i++; 10 k++; 11 } 12 else 13 { 14 r1[k]=r[j]; 15 j++; 16 k++; 17 } 18 } 19 if(i<=m) 20 { 21 while(i<=m) 22 { 23 r1[k]=r[i]; 24 i++; 25 k++; 26 } 27 } 28 else 29 { 30 while(j<=t) 31 { 32 r1[k]=r[j]; 33 j++; 34 k++; 35 } 36 } 37 }
然后,一趟遍歷只需要不斷調用一次歸並的算法就可以實現了。
1 void MergePass(int r[] ,int r1[] , int n, int h) 2 { 3 int i=1; 4 while(i<=n-2*h+1) 5 { 6 Merge(r,r1,i,i+h-1,i+2*h-1); 7 i+=2*h; 8 } 9 if(i<n-h+1) Merge(r,r1,i,i+h-1,n); 10 else for(int k=i; k<=n; k++) 11 { 12 r1[k]=r[k]; 13 } 14 }
開始時,有序序列長度為1,結束時,有序序列長度為n,所以,可以用有序序列的長度來控制排序的結束時刻。同時,排序次數為奇數時,還需要將輔助數組中的值放回原數組。
下面給出歸並排序非遞歸算法:
1 void MergeSort(int r[],int r1[], int n) 2 { 3 int h=1; 4 while(h<n) 5 { 6 MergePass(r,r1,n,h); 7 h*=2; 8 MergePass(r1,r,n,h); 9 h*=2; 10 } 11 }
時間復雜度與空間復雜度分析
對於二路歸並排序來說,它的時間復雜度比較直觀,運行一趟需要掃描數據一次,一趟的時間復雜度為O(n)。整個歸並排序需要運行[log2n]趟。所以,總體的時間復雜度為O(nlogn)。
對於空間復雜度,在排序時,算法使用了一個與待排序序列等長的輔助空間來存放結果,所以其空間復雜度為O(n)。
所以說,二路歸並排序是一種穩定的排序方法,它的最好、最壞、平均的時間復雜度相等。
下面給出完整代碼:
1 #include<iostream> 2 using namespace std; 3 4 void Merge(int r[],int r1[],int s,int m,int t) 5 { 6 int i=s,j=m+1,k=s; 7 while(i<=m&&j<=t) 8 { 9 if(r[i]<=r[j]) 10 { 11 r1[k]=r[i]; 12 i++; 13 k++; 14 } 15 else 16 { 17 r1[k]=r[j]; 18 j++; 19 k++; 20 } 21 } 22 if(i<=m) 23 { 24 while(i<=m) 25 { 26 r1[k]=r[i]; 27 i++; 28 k++; 29 } 30 } 31 else 32 { 33 while(j<=t) 34 { 35 r1[k]=r[j]; 36 j++; 37 k++; 38 } 39 } 40 } 41 42 void MergePass(int r[] ,int r1[] , int n, int h) 43 { 44 int i=1; 45 while(i<=n-2*h+1) 46 { 47 Merge(r,r1,i,i+h-1,i+2*h-1); 48 i+=2*h; 49 } 50 if(i<n-h+1) Merge(r,r1,i,i+h-1,n); 51 else for(int k=i; k<=n; k++) 52 { 53 r1[k]=r[k]; 54 } 55 } 56 57 void MergeSort(int r[],int r1[], int n) 58 { 59 int h=1; 60 while(h<n) 61 { 62 MergePass(r,r1,n,h); 63 h*=2; 64 MergePass(r1,r,n,h); 65 h*=2; 66 } 67 } 68 69 int main() 70 { 71 int a[10000]; 72 int a1[10000]; 73 int n; 74 cin>>n; 75 for(int i=1;i<=n;i++) cin>>a[i]; 76 MergeSort(a,a1,n); 77 for(int i=1;i<=n;i++) cout<<a[i]<<" "; 78 cout<<endl; 79 return 0; 80 }