【合并排序】
又称为归并排序,合并排序是台湾所称?
分治模式: 分解 解决 合并
分解:将n个元素分成两个n/2个元素的子序列
解决:用合并排序法对两个子序列递归地排序
合并:合并两个已排序的子序列以得到排序结果
(对子序列排序时,其长度为1时递归结束。每个元素被视为以排序的)
【合并排序,源自算法导论】
MERGE(A,p,q,r)
n1 = q-p+1
n2 = r-q
create arrays L[1..n1+1] and R[1..n2+1]
for i = 1 to n1
L[i] = A[p+i-1]
for j = 1 to n2
R[j] = A[q+j]
L[n1+1] = ∞
R[n2+1] = ∞
i = 1
j = 1
for k = p to r
if L[i] <= R[j]
A[k] = L[i]
i=i+1
else
A[k] = R[j]
j=j+1
MERGE-SORT(A,p,r)
if p < r
q = [(p+r)/2]
MERGE-SORT(A,p,q)
MERGE-SORT(A,q+1,r)
MERGE(A,p,q,r)
【C++ 代码一】
修改于2013/4/5
#include <iostream> #include <stdio.h> #include <cstring> #include <math.h> #include <time.h> #include <cstdlib> #include <stack> using namespace std; const int IMAX = 100000; const int N = 1000; int *L = new int[N]; int *R = new int[N]; void Merge(int *A,int p,int q,int r) { int i,j; int len_l = q-p+1; int len_r = r-q; for(i = 0;i<len_l;i++) L[i]=A[p+i]; L[len_l] = IMAX; for(j = 0;j<len_r;j++) R[j]=A[q+j+1]; R[len_r] = IMAX; i = j = 0; for(int k=p;k<=r;k++) { if(L[i] <= R[j]) A[k] = L[i++]; else A[k] = R[j++]; } } void Merge_Sort(int *A,int p,int r) { if(p < r) { int q = (p+r)/2; Merge_Sort(A,p,q); Merge_Sort(A,q+1,r); Merge(A,p,q,r); } } int main() { const int num = 10; int Arr[num]; srand((unsigned)time(NULL)); for(int i=0;i<num;i++) Arr[i] = rand()%100; cout<<"before quick sort:"<<endl; for(int i=0;i<num;i++) cout<<Arr[i]<<" "; cout<<endl; Merge_Sort(Arr,0,num-1); cout<<"after quick sort:"<<endl; for(int i=0;i<num;i++) cout<<Arr[i]<<" "; cout<<endl; delete [] L; delete [] R; return 0; } /* 实验结果: before quick sort: 69 80 86 49 35 66 12 96 71 29 after quick sort: 12 29 35 49 66 69 71 80 86 96 */
【C++ 代码二 带详细注释】
写于2011/12/25
#include <iostream> #include <climits> #include <stdlib.h> using namespace std; /*将两段序列按顺序合成一段*/ void Merge(int *a,int p,int q,int r) { int i,j; int len_l=q-p+1; //左序列长度 int len_r=r-q; //右序列长度 int *left=(int *)malloc(sizeof(int)*(len_l+2)); //为左序列申请空间 int *right=(int *)malloc(sizeof(int)*(len_r+2));//为右序列申请空间 for(i=1; i<=len_l; i++) //将a[p...q]放在左序列中 { left[i]=a[p+i-1]; } left[len_l+1]=INT_MAX;//在左序列最后一个位置放置一个哨兵 for(j=1; j<=len_r; j++) //将a[q+1...r]放在右序列中 { right[j]=a[q+j]; } right[len_r+1]=INT_MAX;//在右序列最后一个位置放置一个哨兵 //下面的思想是已经有两端序列:left,right,并且这两段都是 //排好序的。现在比较这两段的第一张,然后抽掉(也就是i++或j++) //张较小的放入到A[k]中,k++,继续比较这两段的第一张,直至没有元素为止。 //哨兵的作用是告诉程序,这一段已经结束了,直接取另一段的放入A[k++]中即可。 //哨兵是这么工作的:如果有一段先结束,那么这一段的第一张就是哨兵了 //另一段肯定比哨兵小,所以放入A数组的一直就是这另一段,直至另一段也有了哨兵。 i=j=1; for(int k=p; k<=r; k++) { if(left[i] <= right[j]) { a[k]=left[i]; i++; } else { a[k]=right[j]; j++; } } } /*将一段序列分为两段,a[p...q],a[q+1..r],然后在再合并*/ void MergeSort(int *a,int p,int r) { //此处默认单独一个数是已经排完序的。 //程序不断递归调用,直到p==r也就是一个数的时候。 //然后再一步步合并,(1,1)合并成2,(2,2)合并成4。。 if(p<r) { int q=(p+r)/2; MergeSort(a,p,q); MergeSort(a,q+1,r); Merge(a,p,q,r); } } int main() { int array[8]= {1,3,5,2,4,7,0,1}; int len=sizeof(array)/sizeof(int); MergeSort(array,0,len-1); for(int i=0; i<len; i++) cout<<array[i]<<" "; return 0; }