十大排序之归并排序(C语言实现)(排序算法)(递归和非递归)

归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。归并排序是一种稳定的排序方法。
时间复杂度O(n log n)
空间复杂度T(n)

首先归并排序分为递归和非递归两种方式。
第一种是递归。
这种递归方式是将两个有序数组进行合并,那么时间复杂度就是O(N)了,我们还需要一个临时数组来存排序好的数组的值,最后将临时数组赋给原来的数组。
我们来看一下代码

void MergeSort(int sourceArr[], int tempArr[], int startIndex, int endIndex)
{
    int midIndex;
    if(startIndex < endIndex)
    {
        midIndex = startIndex + (endIndex-startIndex) / 2;//避免溢出int
        MergeSort(sourceArr, tempArr, startIndex, midIndex);//递归排序左边序列
        MergeSort(sourceArr, tempArr, midIndex+1, endIndex);//递归排序右边序列
        Merge(sourceArr, tempArr, startIndex, midIndex, endIndex);//合并
    }
}
 
int main()
{
    int a[8] = {50, 10, 20, 30, 70, 40, 80, 60};
    int i, b[8];
    MergeSort(a, b, 0, 7);
    for(i=0; i<8; i++)
        printf("%d ", a[i]);
    printf("\n");
    return 0;
}

我们再来看一下合并函数:

void Merge(int sourceArr[],int tempArr[], int startIndex, int midIndex, int endIndex)
{
    int i = startIndex, j=midIndex+1, k = startIndex;
    while(i<=midIndex && j<=endIndex)
    {
        if(sourceArr[i] > sourceArr[j])
            tempArr[k++] = sourceArr[j++];
        else
            tempArr[k++] = sourceArr[i++];
    }
    while(i <= midIndex)
        tempArr[k++] = sourceArr[i++];
    while(j <= endIndex)
        tempArr[k++] = sourceArr[j++];
    for(i=startIndex; i<=endIndex; i++)
        sourceArr[i] = tempArr[i];
}

总代码如下:

#include <stdlib.h>
#include <stdio.h>
 
void Merge(int sourceArr[],int tempArr[], int startIndex, int midIndex, int endIndex)
{
    int i = startIndex, j=midIndex+1, k = startIndex;
    while(i<=midIndex && j<=endIndex)
    {
        if(sourceArr[i] > sourceArr[j])
            tempArr[k++] = sourceArr[j++];
        else
            tempArr[k++] = sourceArr[i++];
    }
    while(i <= midIndex)
        tempArr[k++] = sourceArr[i++];
    while(j <= endIndex)
        tempArr[k++] = sourceArr[j++];
    for(i=startIndex; i<=endIndex; i++)
        sourceArr[i] = tempArr[i];
}
void MergeSort(int sourceArr[], int tempArr[], int startIndex, int endIndex)
{
    int midIndex;
    if(startIndex < endIndex)
    {
        midIndex = startIndex + (endIndex-startIndex) / 2;//避免溢出int
        MergeSort(sourceArr, tempArr, startIndex, midIndex);
        MergeSort(sourceArr, tempArr, midIndex+1, endIndex);
        Merge(sourceArr, tempArr, startIndex, midIndex, endIndex);
    }
}
 
int main()
{
    int a[9] = {50, 10, 20, 30, 70, 40, 80, 60,100};
    int i, b[9];
    MergeSort(a, b, 0, 8);
    for(i=0; i<9; i++)
        printf("%d ", a[i]);
    printf("\n");
    return 0;
}

第二种是非递归算法
我们来看一下步骤
在这里插入图片描述
在这里插入图片描述
因为非递归是不断调用栈的,所以不想递归那样占用内存很大。
首先是排序函数

void Merge_sort(int a[],int N)
{
	int length=1;
	int *temp;
	temp=(int*)malloc(N*sizeof(int));
	if(temp!=NULL)
	{
		while(length<N)
		{
		Merge_pass(a,temp,N,length);//先从最小的序列开始
		length*=2;//每次加倍
		}
		free(temp);//最后释放,不占用空间
	}
	else
		printf("空间不足");
}

然后是内部函数

void Merge_pass(int a[],int temp[],int N,int length)
{
	int i;
	for(i=0;i<=N-2*length;i+=2*length)//每次加倍,因为每次都是偶数序列,最后可能保留一个序列。
	{
		Merge(a,temp,i,i+length,i+2*length-1);//合并有序序列
	}
	if(i+length<N)//是偶数序列
	{
		Merge(a,temp,i,i+length,N-1);
	}
}

关于合并的函数

void Merge(int a[],int temp[],int L,int R,int RightEnd)
{
/* 将有序的A[L]~A[R-1]和A[R]~A[RightEnd]归并成一个有序序列 */
	int Leftend,t;
	int i;
	t=L;
	Leftend=R-1;//左边最后一个元素位置
	while(L<=Leftend&&R<=RightEnd)
	{
		if(a[L]>a[R])
			temp[t++]=a[R++];
		else
			temp[t++]=a[L++];
	}
	while(L<=Leftend)temp[t++]=a[L++];
	while(R<=RightEnd)temp[t++]=a[R++];
 	for(i=RightEnd;i>=0;i--)
	a[i]=temp[i];


}

总代码如下

#include <stdlib.h>
#include <stdio.h>
void Merge_sort(int a[],int N);
void Merge_pass(int a[],int temp[],int N,int length);
void Merge(int a[],int temp[],int L,int R,int RightEnd);
int main()
{
	int a[9]={1,3,4,2,5,6,7,11,8};
	Merge_sort(a,9);
	for(int i=0;i<9;i++)
		printf("%d",a[i]);
	return 0;
}
void Merge_sort(int a[],int N)
{
	int length=1;
	int *temp;
	temp=(int*)malloc(N*sizeof(int));
	if(temp!=NULL)
	{
		while(length<N)
		{
		Merge_pass(a,temp,N,length);
		length*=2;
		}
		free(temp);
	}
	else
		printf("空间不足");
}
void Merge_pass(int a[],int temp[],int N,int length)
{
	int i;
	for(i=0;i<=N-2*length;i+=2*length)
	{
		Merge(a,temp,i,i+length,i+2*length-1);
	}
	if(i+length<N)
	{
		Merge(a,temp,i,i+length,N-1);
	}
}
void Merge(int a[],int temp[],int L,int R,int RightEnd)
{
	int Leftend,t;
	int i;
	t=L;
	Leftend=R-1;//左边最后一个元素位置
	while(L<=Leftend&&R<=RightEnd)
	{
		if(a[L]>a[R])
			temp[t++]=a[R++];
		else
			temp[t++]=a[L++];
	}
	while(L<=Leftend)temp[t++]=a[L++];
	while(R<=RightEnd)temp[t++]=a[R++];
for(i=RightEnd;i>=0;i--)
a[i]=temp[i];
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值