二路归并是指把两个有序序列合并成一个新的有序序列的过程。方法:新建一个序
列,其长度等于要合并的两个序列的长度之和。我们称要合并的序列为A和B,新建的为C。然后设置3个指针:t1、t2、t3,分别指向A、B、C的第一个元素。比较t1,t2指向元素的大小,将较小的存储在C中t3所指的位置,并将指向较小元素的指针和t3都向后移一位。重复上述操作,直到A或B序列已经全部存入C中。最后把另一序列的剩余部分赋值到C序列的后半部分。此时C就是一个有序序列。
二路归并排序的思想:采用递归的方法把原序列分割成两个子序列,再把子序列也分成两个子序列,直到两个子序列的长度都为一时,进行二路归并,使这个子序列变为有序序 列。再把已得到的有序子序列进行合并。最终会使整个序列变为有序序列。
举例:(括号内的是有序序列)
初始序列 [51] [33] [62] [96] [87] [17] [28]
一趟二路归并排序后 [33 51] [62 96] [17 87] [28]
二趟二路归并排序后 [33 51 62 96] [17 28 87]
三趟二路归并排序后 [17 28 33 51 62 87 96]
二、过程
procedure merge(p,q:integer);
var s,e,t1,t2,f,k:integer;
begin
if q=p then exit;
f:=(p+q) div 2;
merge(p,f);
merge(f+1,q);
fillchar(b,sizeof(b),0);
t1:=p; t2:=f+1;
k:=p-1;
while (t1<=f) and (t2<=q) do begin
inc(k);
if a[t1]<=a[t2] then begin {“<=”是保持算法稳定性的关键}
b[k]:=a[t1];
inc(t1);
end
else begin
b[k]:=a[t2];
inc(t2);
end;
end;
e:=0;
if t1<=f then begin s:=t1; e:=f; end;
if t2<=q then begin s:=t2; e:=q; end;
for i:=s to e do b[i+k-s+1]:=a[i];
for i:=p to q do a[i]:=b[i];
end;
三、评价
归并排序的时间复杂度是O(nlog2n)。归并排序是一种稳定的排序算法。
---------------------------------------------------
归并排序的主要思想是:把待排序的记录序列分成若干个字序列,先将每个子序列的记录排序,再将已排序的子序列合并,得到完全排序的记录序列。归并排序可分为多路归并排序和二路归并排序。
一趟归并排序算法:void Merge(RecordType a[],RecordType b[],int i,int m,int n)
/* 将有序表a[i..m]以及a[m+1..n]有序归并到b[i..n]中 */
{
int la,lb,lc;
la=i;lb=m+1;lc=i; /*序列la,lb,lc的始点*/
while(la<=m&&lb<=n)
{
if(a[la].key<a[lb].key)
b[lc++]=a[la++];/*有序合并*/
else
b[lc++]=a[lb++];
}
while(la<=m)
b[lc++]=a[la++];/*复制第一个序列中剩下的元素*/
while(lb<=n)
b[lc++]=a[lb++];/*复制第二个序列中剩下的元素*/
}
归并排序算法:void MergePass(RecordType R[],RecordType A[],int n,int c)
/*把序列R[0..n-1]以长度为c的序列进行两两归并,归并后存在序列A中*/
{
int i=0,j;
while(i+2*c-1<=n-1) /*长度均为c的两个子序列合并为一个序列*/
{
Merge(R,A,i,i+c-1,i+2*c-1);
i+=2*c;
}
if(i+c-1<n) /*长度不等的两个子序列合并为一个序列*/
{
Merge(R,A,i,i+c-1,n-1);
}
else
for(j=i;j<=n-1;j++) /*仅剩一个序列时,直接复制到A中*/
A[j]=R[j];
}
归并排序的时间复杂度为O(nlog2n),利用二路归并排序时,需要利用与待排序序列长度相同的数组作为临时存储单元,故该排序方法的空间复杂度O(n)。void MergeSort(RecordType R[],int n)
/*对表r中的第0到第n-1个记录进行归并排序*/
{
int c=1; /*每次归并的长度,初始为1*/
RecordType A[MAXSIZE]; /*需要一个辅助空间*/
while(c<n)
{
MergePass(R,A,n,c);/*一次合并,结果存入A中*/
c*=2; /*序列长度扩大一倍*/
MergePass(A,R,n,c);/*再次合并,结果存入R中*/
c*=2;
}}