归并排序(递归详解)

归并排序:十大排序算法之一,才用的是分而治之的方法。

简单来说就是(百度百科):

其主要算法操作可以分为以下步骤:

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;
}

使用时注意函数、参数命名问题。俗话说:“命名不规范,亲人两行泪。”

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值