合并排序算法是用分治策略实现对n个元素进行排序的算法。其基本思想是:将待排元素分成大小大致相同的两个子集合,
分别对这两个子集合进行排序,最终将排好序的子集合合并成所要求的排好序的集合。其中,算法Merge合并两个排好序的数组
段到一个新的数组b中,然后由Copy将合并后的数组段再复制回数组a中。对于MergeSort,可以从分治策略的机制入手,容易
消除算法的递归。事实上,递归过程只是将待排序的集合一分为二,直至待排序集合只剩下一个元素为止,然后不断合并两个排
好序的数组段。按此机制,可以首先将数组a中相邻元素两两配对。用合并算法将它排序,构成n/2组长度为2的排好序的子数组
段,然后再将它们排序成长度为4的排好序的子数组段,如此继续,直至整个数组排好序。而自然合并是上述合并算法的一个变
形。在上述合并算法中,第一步合并相邻长度为1的子数组段,因为长度为1的子数组段是排好序的。事实上,对于原先给定的数
组,通常存在多个长度大于1的以及排好序的子数组段。用一次扫描就可找出所有这些排好序的子数组段。然后将相邻的排好序
的子数组段两两合并,构成更大的排好序的子数组段,继续如此,直至整个数组排好序。
以下是完整代码:
#include <stdio.h>
#include <string.h>
#define N 7
int index[N],flag = 0;//index数组用来记录每个自然分组的起始下标 flag用来记录共有多少组
void getindex(int a[],int index[])
{
int i;
index[flag++] = 0;//起始分组从下标0开始最少有一组
for(i = 0;i < N-1; i++)
{
if(a[i+1]<a[i])
index[flag++] = i+1;
}
for(i = 0; i< flag; i++)
printf("%d ",index[i]);
printf("\n");
}
//Merge函数功能: 合并src[left:middle]和src[middle+1:right]到dst[[left:right]
//l=第一个自然分组第一位下标; m=第一个自然分组最后一位下标; r=第二个自然分组最后一位下标
void Merge(int a[], int b[],int l, int m, int r)
{
int i=l,j=m+1,z=l;
while(i<=m&&j<=r)
{
if(a[i]<a[j])
{
b[z++] = a[i++];
}
else
{
b[z++] = a[j++];
}
}
while(i<=m)
b[z++] = a[i++];
while(j<=r)
b[z++] = a[j++];
}
//MergePass函数功能:合并自然分组后相邻的子数组
void MergePass(int a[], int b[], int s)
{
int i=0;//表示第几段 注意一定要赋初值不然下面比较会异常!!!找这个bug找了很久!!!
//while功能:当自然分组后的子数组个数为偶数时, r = arrayA_Length, 表示恰好两两合并
while(i<=flag - 2 * s)//最多只有flag个段
{
int r = ((i+2*s)<flag)? index[i+2*s]:N;
Merge(a,b,index[i],index[i+s]-1,r-1);//把两个长度为s的两数组合并
i=i+2*s;
}
if(i+s < flag)
Merge(a,b,index[i],index[i+s]-1,N-1);
else
{
int j;
for(j = index[i]; j<=N-1; j++)//剩余不够拼组的元素直接合并
{
b[j] = a[j];
}
}
}
void MergeSort(int a[])
{
int s = 1;//第s轮排序,每次合并s个分组
// printf("%d",s);
int b[N];
int i;
//while功能:数组a合并到数组b,数组B再合并到数组a,一直合并到完全合并,而且最后是输出a数组
while(s < flag)
{
MergePass(a,b,s);//将a合并到b中
s += s;
MergePass(b,a,s);//将b合并到a中
s += s;
}
for(i=0;i<N;i++){
printf("%d ",b[i]);
}
printf("\n");
}
int main(){
int a[N] = {5,7,4,8,6,3,2};
int n = 7;
getindex(a,index);//存储每个自然分组的起始下标
MergeSort(a);//归并排序
return 0;
}