利用自然分组的合并排序(C语言)

         合并排序算法是用分治策略实现对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;
}

 

点赞