形象視頻:http://v.youku.com/v_show/id_XMzMyODk5Njg4.html
將兩個有序的子序列[low,m]和[m,high]歸併成一個有序的序列。合併過程中,設置i,j和p三個指針,其初值分別指向這三個記錄區的起始位置。合併時以此比較arr[i]和arr[i],取較小的記錄複製到arr1[p],然後將i或j,以及p均+1。
void MergeSort(int *arr,int low,int m,int high)
{
int i,j,p;
int *arr1;//緩存向量
i=low;
j=m+1;
p=0;
while(i<=m&&j<=high)//兩序列非空時,將較小的輸出到向量arr1中
{
if(arr[i]<arr[j])
{
arr1[p]=arr[i];
p++;
i++
}
else
{
arr1[p]=arr[j];
p++;
j++;
}
}
while(i<=m)//若該子序列非空,則將剩餘的記錄記錄到arr1中
{
arr[p]=arr1[i];
p++;
i++
}
while(j<=high)//若該子序列非空,則將剩餘的記錄記錄到arr1中
{
arr[p]=arr1[j];
p++;
j++;
}
for(i=low,p=0;i<=high;i++,p++)
arr[i]=arr1[p];
}
1 自底向上的方法
基本思路:第一趟歸併排序時,將待排序的arr[0...n]看作是 n個長度爲1的有序子文件,將這些子序列兩兩歸併,若n爲偶數則得到n/2個長度爲2的有序序列;若n爲奇數,則最後一個子序列輪空(不參與歸併),因此本次歸併後得到錢lgn個有序子序列長度爲2,但最後一個子序列長度仍爲1。第二趟歸併則將第一趟歸併所得到lgn個有序子序列兩兩歸併,如此反覆,直到得到一個長度爲n的有序序列爲止。上述每次歸併,均是將兩個有序的子序列合併成一個有序子序列,故稱其爲“二路歸併排序”
代碼分析:在某趟歸併中,設各子序列長度爲length,則歸併序列arr[0..n]中有序子序列:[1..length],[length+1....2length],.....,[n/length-1]*length+1.....n]。
在調用歸併操作將相鄰的一對子序列進行歸併時,必須考慮兩個問題:1子序列個數是奇數,2最後一各子序列長度小於length,對應的作如下處理,
1.若子序列個數爲奇數,則最後一個子序列無須和其他子序列歸併,即本趟輪空;
2.若子序列個數爲偶數,要注意最後一對子序列中後一個序列的區間上界應該是n;
void MergePass(int *arr,int length)
{
int i;
//歸併長度爲length的兩個相鄰子序列
for(i=1;i+2*length-1<=n;i=i+2*length)
MergeSort(arr,i,i+length-1,i+2*length-1);
//上述循環執行完後,arr數組中保存的是n/length個長度爲length的有序子序列
//如果還剩下兩個子序列,後者的長度小於length,則設置後者的區間上限爲n
if(i+length-1<n)
MergeSort(arr,i,i+length-1,n)
//如果i<=n&&i+length-1>=n,也即n爲奇數時,默認剩餘的一個那個元素無須歸併
}
//採用自底向上的方法,對arr[1....n]進行2路歸併
void Merge(int *arr)
{
int length;
for(length=1;length<n;length*=2)//作lgn趟歸併
MergePass(arr,lenth);
}
2 自頂向下的方法【待研究】
採用分治法進行自頂向下的算法設計,形式更爲簡潔。
設歸併排序的當前區間是R[low..high],分治法的三個步驟是:
①分解:將當前區間一分爲二,即求分裂點
②求解:遞歸地對兩個子區間R[low..mid]和R[mid+1..high]進行歸併排序;
③組合:將已排序的兩個子區間R[low..mid]和R[mid+1..high]歸併爲一個有序的區間R[low..high]。
遞歸的終結條件:子區間長度爲1(一個記錄自然有序)。
void MergeSortDC(SeqList R,int low,int high)
{//用分治法對R[low..high]進行二路歸併排序
int mid;
if(low<high){//區間長度大於1
mid=(low+high)/2; //分解
MergeSortDC(R,low,mid); //遞歸地對R[low..mid]排序
MergeSortDC(R,mid+1,high); //遞歸地對R[mid+1..high]排序
Merge(R,low,mid,high); //組合,將兩個有序區歸併爲一個有序區
}
}//MergeSortDC
時間複雜度:對長度爲n的序列,需要進行lgn趟二路歸併,每趟歸併時間複雜度爲O(n),所以好或壞的情況下時間複雜度均爲O(nlgn)
空間複雜度:需要額外的向量保存結果,空間複雜度爲O(n)
屬於不穩定排序
參考:http://hi.baidu.com/sleet1986/blog/item/82f0ae8b6b4e38609f2fb4cd.html