把数据分为两段,从两端中逐个选最小的元素移入新数据段的末尾(可从上到下或从下到上进行)。
- 归并排序(Merging Sort):
原理:假设初始序列含有 n 个记录,则可以看成时n个有序的子序列,每个子序列的长度为1,然后两两归并,得到 [n/2] ([x]表示不小于x的最小整数) 个长度为2或1的有序子序列;再两两归并,一直重复,直至得到一个长度为n的有序列为止,这种序列方法称为 2 路归并排序。
//对顺序L作归并排序
void MergeSort(SqList *L)
{
MSort(L->r,L->r,1,L->length);
}
- 对数组 {50,10,90,30,70,40,80,60,20}进行排序,L.length=9,MSort的实现:
//将SR[s..t]归并排序为TR1[s..t]
void MSort(int SR[],int TR1[],int s,int t)
{
int m;
int TR2[MAXSIZE+1];
if(s==t)
TR1[s]=SR[s];
else
{
m=(s+t)/2; //将SR[s..t平分为SR[s..m]和SR[m+1..t]]
MSort(SR,TR2,s,m);//递归将SR[m+1..t]归并为有序TR2[m+1..t]
Merge(TR2,TR1,s,m,t); //将TR2[s..m]和TR2[m+1..t] 归并到TR1[s..t]
}
}
- MSort被调用时,SR与TR1都是{50,10,90,30,70,40,80,60,20},s=1,t=9,最终我们的目的就是要将TR1中的数组排好顺序。
- s!=t,执行else
- m=(s+t)/2 ——>m=(1+9)/2=5,m就是序列正中间下标。
- Merge函数的代码实现:
//将有序的SR[i..m]和SR[m+1..n]归并为有序的TR[i..n]
void Merge(int SR[],int TR[],int i,int m,int n)
{
int j,k,l;
for(j=m+1,k=i;i<=m&&j<=n;k++) //将SR中记录由小到大归并入TR
{
if(SR[K]<SR[j])
TR[k]=SR[i++];
else
TR[k]=SR[j++];
}
if(i<=m)
{
for(l=0;l<=m-i;l++)
TR[k+l]=SR[i+l]; //将剩余的SR[i..m]复制到TR
}
if(j<=n)
{
for(l=0;l<=n-j;l++)
TR[k+l]=SR[j+l]; //将剩余的SR[j..n]复制到TR
}
}
归并排序是一种比较占用内存,效率高且稳定的算法。
- 非递归实现归并排序
//对顺序L作归并非递归排序
void MergeSort2(SqList *L)
{
int* TR=(int*)malloc(L->length*sizeof(int)); //申请额外空间
int k=l;
while(k<L->length)
{
MergePass(L->r,TR,k,L->length);
k=2*k; //子序列长度加倍
MergePass(TR,L->r,k,L->length);
k=2*k; //子序列长度加倍
}
}
- 数组L为{50,10,90,30,70,80,60,20},L.length=9;
- 用malloc来申请额外的内存空间,用来存放归并结果。
- while循环,不断的归并有序序列。注意k值的变化,在不断循环中,跳出循环。
MergePass代码实现:
//将SR[]中相邻长度为s的子序列两两归并到TR[]
void MergePass(int SR[],int TR(),int s,int n)
{
int i=1;
int j;
while(i<=n-2*s+1)
{
Merge(SR,TR,i,i+S-1,i+2*s-1); //两两归并
i=i+2*s;
}
if(i<n-s+1) //归并最后两个序列
Merge(SR,TR,i,i+s-1,n);
else
for(j=i;j<=n;j++)
TR[j]=SR[j];
}
- “MergePass(L.r,TR,k,L.length);”,L.r是初始无状态,TR为申请的空数组,k=1,L.length=9
- while循环目的是使两两归并,因s=1,n-2*s+1=8。