分治演算法--歸併排序
阿新 • • 發佈:2019-02-12
一.基本思想與步驟
歸併排序法(Merge Sort,以下簡稱MS)是分治法思想運用的一個典範。直觀上其操作如下:
Merge-Sort
——Divide-and-Conquer(P)
1. 如果子序列長度為1,排序完成。
—— if |P|≤n0, thenreturn(ADHOC(P))
2. 分解待排序的n個元素的序列成各具n/2個元素的子序列。
——將P分解為較小的子問題 P1 ,P2,...,Pk。
3. 遞迴排序兩個子序列。
——for i←1 to k,do yi ←Divide-and-Conquer(Pi)△遞迴解決Pi。
4. 合併兩個已排序的子序列以產生已排序的答案。
——T ← MERGE(y1,y2,...,yk)△合併子問題, return(T)。
當待排序的序列長度為1時,即已牌號序,遞迴“開始回升”,不做任何操作。
歸併排序的關鍵在於MERGE合併已排序子序列,類如玩撲克牌,假設桌面上有已經排好序的兩堆撲克牌,如何合併成單一有序輸出堆。演算法導論實現虛擬碼如下:
現在將MERGE作為一個子程式應用。下面MERGE-SORT(A,p,r)排序A[p..r]中元素,若p>=r,則子陣列最多一個元素,即已經劃分完成,且已排序完成。否則,分解成A[p..mid]A[mid+1..r]兩個子陣列,遞迴呼叫MERGE-SORT。虛擬碼如下:MERGE(A,p,mid,r) n1 = mid – p + 1, n2 = r – mid; Let L[1…n1] and R[1…n2] be new arrays; For i = 1 to n1 L[i] = A [p+i-1]; For i = 1 to n2 R[i] = A [mid+i]; L[n1+1] = R[n2+1] = MAX; i = 1 , j =1; For( k = p to r If L[i] < R[j] A[k] = L[i++]; Else A[k] = R[j++];
MERGE-SORT(A,p,r)
If(p<r)
Mid = (p+r)/2;
MERGE-SORT(A,p,mid);
MERGE-SORT(A,mid+1,r);
MERGE(A,p,mid,r);
#include<stdio.h> #define MAX 0x3f3f3f void Merge(int a[],int l,int m,int u) { int i,j=0,k=0; int *b=new int[m-l+1]; int *c=new int[u-m]; for(i=0;i<m-l+1;i++) b[i]=a[l+i-1]; b[i]=MAX; for(i=0;i<u-m;i++) c[i]=a[m+i]; c[i]=MAX; for(i=l-1;i<u;i++) { if(b[j]<=c[k]) a[i]=b[j++]; else a[i]=c[k++]; } /* puts("test"); for(i=l-1;i<u;i++) printf("%d ",a[i]); puts(""); */ } void Mergesort(int a[],int begin,int end) { int mid=(begin+end)/2; if(begin<end) { Mergesort(a,begin,mid); Mergesort(a,mid+1,end); Merge(a,begin,mid,end); } } int main() { int a[20]; int i; for(i=0;i<20;i++) scanf("%d",&a[i]); Mergesort(a,1,20); for(i=0;i<20;i++) printf("%d ",a[i]); puts(""); return 0; }
二.複雜度分析
時間複雜度為O(nlogn) 這是該演算法中最好、最壞和平均的時間效能。空間複雜度為 O(n)。比較操作的次數介於(nlogn) / 2和nlogn - n + 1。賦值操作的次數是(2nlogn)。歸併演算法的空間複雜度為:0 (n)。歸併排序比較佔用記憶體,但卻是一種效率高且穩定的演算法。