归并排序(递归实现)

归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法。
归并过程为:比较a[i]和b[j]的大小,若a[i]≤b[j],则将第一个有序表中的元素a[i]复制到r[k]中,并令i和k分别加上1;否则将第二个有序表中的元素b[j]复制到r[k]中,并令j和k分别加上1,如此循环下去,直到其中一个有序表取完,然后再将另一个有序表中剩余的元素复制到r中从下标k到下标t的单元。归并排序的算法我们通常用递归实现,先把待排序区间[s,t]以中点二分,接着把左边子区间排序,再把右边子区间排序,最后把左区间和右区间用一次归并操作合并成有序的区间[s,t]。

下段代码中,将a[] 和 b[]合并到一个数组T[]

int a[5] = {1,3,5,7,9};
int b[5] = {,2,4,6,8,10};
int T[10] = {0};
for(int i =0;i<5;i++)
    T[i] = a[i];
for(int i =5;i<10;i++)
    T[i] = b[i];

再进行归并

#include "stdio.h"

void Merge(int A[],int TempA[],int L,int R,int RightEnd)
{
    int LeftEnd = R-1;    //左边终点位置
    int temp = L;       //存放结果排序后的数组的初始位置
    int NumElements = RightEnd-L+1;  //记录总数
    while(L<=LeftEnd && R<= RightEnd)
    {
        if(A[L]<=A[R]) TempA[temp++] = A[L++];/* 将左边元素复制到TmpA */
        else    TempA[temp++] = A[R++];/* 将右边元素复制到TmpA */
    }
    while(L<=LeftEnd)
        TempA[temp++] = A[L++];/* 直接复制左边剩下的 */
    while(R<=RightEnd)
        TempA[temp++] = A[R++];  /* 直接复制右边剩下的 */
    for( i = 0; i < NumElements; i++, RightEnd -- )
         A[RightEnd] = TmpA[RightEnd]; /* 将有序的TmpA[]复制回A[] */

}

int main()
{
    int a[10]={1,3,5,7,9,2,4,6,8,10};
    int b[10]={0};
    Merge(a,b,0,5,9);
    for(int i =0;i<10;i++)
        printf("%d",a[i]);
    return 0;
}

当然,你会有疑问,为什么给我们的两个数组,一开始就是已经排好序的?其实上面只是演示的过程。在现实的问题中,往往会给我们一个杂乱无序的数组。结合上面的例子,我们可以尝试这么做:分而治之。如下图所示:

这里写图片描述

分而治之的关键在于:
将一个无序的数组分成等分的两小段。接着呢,又可以将两小段每一段再分。。。不断重复直到每一段都无法再分的时候,也就是每一段,都只有一个元素的时候,无法再分,即下面代码中 L<RightEnd 的时候,将数组中的数通过归并排序的核心算法进行排序,并保存到TempA[]中。
注意这是递归。

void MSort(int A[],int TempA[],int L,int RightEnd)
{/* 核心递归排序函数 */ 
    int Center;
    if(L<RightEnd){
        Center = (L+RightEnd)/2;
        MSort(A,TempA,L,Center); /* 递归解决左边 */ 
        MSort(A,TempA,Center+1,RightEnd);/* 递归解决右边 */  
        Merge(A,TempA,L,Center+1,RightEnd);/* 合并两段有序序列 */ 
    }
}

这里写图片描述

之后,在将TempA[] 中的数据依次保存回A[]

这里写图片描述

我们把上面的代码优化一下,即可以提供统一函数的接口。

void Merge_Sort(int A[],int n)
{/* 归并排序 */
    int *TempA = (int*)malloc(sizeof(int)*n);
    if(TempA !=NULL){
        MSort(A,TempA,0,n-1);
        free(A);
    }
    else Error("空间不足");
}

统一代码:

#include "stdio.h"
#include "stdlib.h"
/* L = 左边起始位置, R = 右边起始位置, RightEnd = 右边终点位置*/
void Merge(int A[],int TempA[],int L,int R,int RightEnd)
{/* 将有序的A[L]~A[R-1]和A[R]~A[RightEnd]归并成一个有序序列 */
    int LeftEnd = R-1;    //左边终点位置
    int temp = L;       //存放结果排序后的数组的初始位置
    int NumElements = RightEnd-L+1;  //记录总数
    while(L<=LeftEnd && R<= RightEnd)
    {
        if(A[L]<=A[R]) TempA[temp++] = A[L++];/* 将左边元素复制到TmpA */
        else    TempA[temp++] = A[R++];/* 将右边元素复制到TmpA */
    }
    while(L<=LeftEnd)
        TempA[temp++] = A[L++]; /* 直接复制左边剩下的 */
    while(R<=RightEnd)
        TempA[temp++] = A[R++]; /* 直接复制右边剩下的 */

   for( i = 0; i < NumElements; i++, RightEnd -- )
         A[RightEnd] = TmpA[RightEnd]; /* 将有序的TmpA[]复制回A[] */
}


void MSort(int A[],int TempA[],int L,int RightEnd)
{/* 核心递归排序函数 */ 
    int Center;
    if(L<RightEnd){
        Center = (L+RightEnd)/2;
        MSort(A,TempA,L,Center); /* 递归解决左边 */ 
        MSort(A,TempA,Center+1,RightEnd);/* 递归解决右边 */  
        Merge(A,TempA,L,Center+1,RightEnd);/* 合并两段有序序列 */ 
    }
}

void Merge_Sort(int A[],int n)
{/* 归并排序 */
    int *TempA = (int*)malloc(sizeof(int)*n);
    if(TempA !=NULL){
        MSort(A,TempA,0,n-1);
        free(A);
    }
    else printf("空间不足\n");
}


int main()
{
    int a[10]={1,3,5,7,9,2,4,6,8,10};
    //int b[10]={0};
    //Merge(a,b,0,5,9);
    Merge_Sort(a,10);
    for(int i =0;i<10;i++)
        printf("%d",a[i]);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值