归并排序:十大排序算法之一,才用的是分而治之的方法。
简单来说就是(百度百科):
其主要算法操作可以分为以下步骤:
Step 1:将n个元素分成两个含n/2元素的子序列
Step 2:用MS将两个子序列递归排序(最后可以将整个原序列分解成n个子序列)
Step 3:合并两个已排序好的序列
易知,MS的关键在于Merge过程。对于这一过程的理解,算法导论中给出了一个形象的模型。
即假设桌面上有两堆已排序好的的牌,且每一堆都正面朝下放置。然后我们分别从两堆牌中选取顶上的一张牌(选取之后,堆顶端又会露出新的顶牌),选取较小的一张,放入输出堆,另一张放回。
重复这一步骤,最后直到一堆牌为空。由于两堆牌都是已排序,所以可知,只要将剩下的那堆牌盖到输出堆即完成整个排序过程。
C语言代码如下:
#include <stdio.h>
#include<stdlib.h>
void ssort(int* a,int*Tmpa,int L,int m,int R)
{
int x = L,y = m,k = L;//x:为比较部分左边开始位置,y:右边开始位置,k:存放的开始位置
for(int i = L;i<m;i++) //将要排序的部分的左边复制到备用数组,为何为左边,因为a的左边要进行存比较后的值
Tmpa[i] = a[i];
while(x<m&&y<=R) //当左边或者右边其中一边的值比较完成,退出比较
{
if(Tmpa[x] < a[y])//比较出较小的值,存放在a正在排序部分的左边
a[k++] = Tmpa[x++]; //取出值,对应比较位置(x,y)向后移动一个,存放位置(k)也要向后移动一个
else
a[k++] = a[y++];
}
while(x < m) //如果左边(Tmpa)还有剩余部分,则是这些比较部分最大的那些值,直接复制到最后。右边则本来就在a比较部分最后,不需要复制。
a[k++] = Tmpa[x++];
}
void Merge_s(int* a,int* Tmpa,int L,int R)
{
if(L<R) //递归约束
{
int m = (L+R)/2; //一分为二
Merge_s(a,Tmpa,L,m);//左
Merge_s(a,Tmpa,m+1,R);//右
ssort(a,Tmpa,L,m+1,R);//最后进行排序,m+1:是因为L和R相差1时,m==L;
}
}
void MergeSort(int* a,int n)
{
int* Tmpa = (int*)malloc(n*sizeof(int)); //排序需要一个大小和他一样大的数组,提前开好,避免后续递归开辟
if(Tmpa != NULL)
{
Merge_s(a,Tmpa,0,n-1);//开始递归
free(Tmpa);
}
}
int main()
{
int arr[11] ={10,9,8,7,6,5,4,3,2,1,0};//待排序数组
MergeSort(arr,11);//调用排序
//排序后的结果
for(int i = 0;i<sizeof(arr)/sizeof(arr[0]);i++)
{
printf("%d ",arr[i]);
}
return 0;
}
使用时注意函数、参数命名问题。俗话说:“命名不规范,亲人两行泪。”