归并排序实现(Chen yue 数据结构)

归并排序

归并排序是通过将待排序列分为若干子序列,一开始分割后的每个子序列长度为1,意思是每个元素单独成为一个序列,此时可以认为当前所有的子序列是“有序的”,那么将这些序列相邻的两两合并,此时形成了log2n个有序的长度为二的子序列,以此类推,直到序列长度为原待排序列长度。

归并排序是采用分治法的思想,将有序的子序列合并,算法稳定,时间复杂度恒为O(nlogn),需要额外的空间,所有空间复杂度较高,常用于外排序(即无法在内存中完成的排序)

递归版本算法

递归版本实现,将待排序列不断二分,直到无法二分,进行排序+归并


#include <stdio.h>
#include <stdlib.h>
//归并排序
//递归算法
//并算法,对数组进行排序
void Merge(int arr[],int left,int rightEnd,int TmpA[],int right)
{
    int leftEnd = right - 1;
    int tmp = left;
    int sum = rightEnd - left +1;
    while(left<=leftEnd&&right<=rightEnd)
    {
        if(arr[left]<arr[right]){TmpA[tmp] = arr[left];left++;}
        else {TmpA[tmp] = arr[right];right++;}
        tmp++;
    }
    while(left<=leftEnd){TmpA[tmp++] = arr[left++];}
    while(right<=rightEnd){TmpA[tmp++] = arr[right++];}
    int i = 0;
    //将tmpA中排好序的数组交给arr
    for(i;i<sum;i++,rightEnd--){arr[rightEnd] = TmpA[rightEnd];}//printf("%d",arr[rightEnd]);}
    printf("\n");
}
//递归执行,将数组分为多个子列,对每个子列进行排序,最后将其归入arr中
void Msort(int arr[],int left,int rightEnd,int TmpA[],int N)
{
    int center;
    if(left<rightEnd)
    {
        center = (rightEnd+left)/2;//取中间
        Msort(arr,left,center,TmpA,N);
        Msort(arr,center+1,rightEnd,TmpA,N);
        Merge(arr,left,rightEnd,TmpA,center+1);
        int i = 0;
        for(i;i<N;i++)printf("%d",arr[i]);
    }
}
//统一函数接口
void Merge_sort(int arr[],int N)
{
    int *tmpA;//在函数接口内声明一个临时数组,空间复杂度最小
    tmpA = (int *)malloc(N*sizeof(int));
   // printf("???");
    //申请到空间,执行归并,否则打印错误信息
    if(tmpA!=NULL)
    {
        Msort(arr,0,N-1,tmpA,N);
        free(tmpA);
    }
    else printf("空间不足\n");
}
int main()
{
    int n;
    scanf("%d",&n);
    int arr[n];
    int i,j;
    for(i=0;i<n;i++)
        scanf("%d",&arr[i]);
    Merge_sort(arr,n);
    for(i;i<n;i++)printf("%d ",arr[i]);
    return 0;
}

非递归版本

子列长度从1一直到n,每次排序归并所有子列,log2n次

#include <stdio.h>
#include <stdlib.h>
//归并排序
//非递归算法
//并算法,对数组进行排序
void Merge(int arr[],int left,int rightEnd,int TmpA[],int right)
{
    int leftEnd = right - 1;
    int tmp = left;
    int sum = rightEnd - left +1;
    //对子列进行比较排序
    while(left<=leftEnd&&right<=rightEnd)
    {
        //比较左右两个子列,进行归并
        if(arr[left]<arr[right]){TmpA[tmp] = arr[left];left++;}
        else {TmpA[tmp] = arr[right];right++;}
        tmp++;
    }
    //比较后剩下的元素
    while(left<=leftEnd){TmpA[tmp++] = arr[left++];}
    while(right<=rightEnd){TmpA[tmp++] = arr[right++];}
}
void Msort(int arr[],int TmpA[],int N,int length)
{
  int i = 0,j;
  //成段处理处理到倒数第二段,因为最后可能出现奇数个数,所以需要单独处理
  //i:0,2,4,6,8
  for(i;i<=N-2*length;i+= 2*length)
    Merge(arr,i,i+2*length-1,TmpA,i+length);
  //i + length < N 剩余个数仍可以分成子列
  if(i+length<N)
    Merge(arr,i,N-1,TmpA,i+length);
    //否则将最后的跟在结果后面
  else
    for(j = i; j<N; j++)TmpA[j]=arr[j];

}
//统一函数接口
void Merge_sort(int arr[],int N)
{
    int *tmpA;//在函数接口内声明一个临时数组,空间复杂度最小
    int length = 1;
    int i = 0;
    tmpA = (int *)malloc(N*sizeof(int));
   // printf("???");
    //申请到空间,执行归并,否则打印错误信息
    if(tmpA!=NULL)
    {
        //
        while(length<N){

            Msort(arr,tmpA,N,length);
            printf("%d\n",length);
            //length*2
            length *=2;
            for(i=0;i<N;i++)printf("%d",tmpA[i]);
            printf("\n");
            Msort(tmpA,arr,N,length);
            for(i=0;i<N;i++)printf("%d",arr[i]);
            printf("%d\n",length);
            length *= 2;
            printf("\n");
        }
        free(tmpA);
    }
    else printf("空间不足\n");
}
int main()
{
    int n;
    scanf("%d",&n);
    int arr[n];
    int i,j;
    for(i=0;i<n;i++)
        scanf("%d",&arr[i]);
    Merge_sort(arr,n);
    for(i=0;i<n;i++)printf("%d ",arr[i]);
    return 0;
}

欢迎纠错。

猜你喜欢

转载自blog.csdn.net/Boolean_starki/article/details/81869054
yue