排序算法—归并排序

归并排序

归并排序(Merge Sort)是利用“归并”技术来进行排序,所谓归并是指将若干个子文件合并为一个文件的过程,由约翰·冯·诺伊曼发明。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。即是将文件先分解再合并,最终得到有序序列。

题目描述

给出一组数据,根据由小到大顺序输出。

输入要求:

输入一个整数n(数据长度)
输入n个数据

输出要求:

输出由小到大排序后的数据

样例输入:

10
37 28 46 19 55 28 92 84 63 71

样例输出:

19 28 28 37 46 55 63 71 84 92

基本思想

假设待排序的数据都存放在数组R[n]中,mid是数组长度的一半,将数组分成R[0] ~ R[mid]和R[mid+1] ~ R[n-1]两个子文件,用递归的方式继续将这两个子文件再各自分解成两部分,直至子文件中只有1个元素,这是分解的过程。然后将两个子文件合并成一个有序文件,直至形成有序序列,这是归并的过程。

在这里插入图片描述

分解的过程利用递归操作即可实现。而排序的重点是归并的过程,即如何将两个文件合并成一个有序序列。以本例最后一次归并过程为例(经过前几次归并后,这两个子文件自身都是有序的),i 和 j 分别指向两个子文件的第一个元素,并定义一个临时数组Temp,i 和 j 位置元素进行比较,将较小的放入临时数组,然后向右继续比较。

在这里插入图片描述

当一个子文件内所有元素都已放入临时数组Temp中,另一个子文件剩余元素无需再比较,因为经过前面的归并子文件本身是有序的,直接依次放入临时数组中即可。

在这里插入图片描述
归并结束后将临时数组Temp中的元素在放回元数组R中。

参考代码(C语言)
#include<stdio.h> 

void merge_sort(int R[],int start,int end); 	//归并排序
void merge(int R[],int start,int mid,int end); 	//归并过程

int main()
{
	int i,R[100],n;
 	scanf("%d",&n);
 	for(i=0;i<n;i++)
 		scanf("%d",&R[i]);
 	merge_sort(R,0,n-1);
 	for(i=0;i<n;i++)
 		printf("%d ",R[i]);
 	return 0;
} 

void merge(int R[],int start,int mid,int end)
{
 	int Temp[end-start+1];	//定义临时数组
 	int i=start;		//i 和 j 分别指向两个子文件的第一个元素
 	int j=mid+1;
 	int k=0;
 	while(i<=mid&&j<=end)	
 	{
  		if(R[i]<=R[j])	//i 和 j 位置元素进行比较,将较小的放入临时数组
   			Temp[k++]=R[i++];
  		else
   			Temp[k++]=R[j++];
 	}
	while(j<=end)		//第一个文件元素都已放入临时数组
  		Temp[k++]=R[j++];	//将第二个文件剩余元素放入临时数组
  	while(i<=mid) 		//第二个文件元素都已放入临时数组
    		Temp[k++]=R[i++];	//将第一个文件剩余元素放入临时数组
 	for(i=0;i<k;i++)
  		R[start+i]=Temp[i];	//将临时数组的元素放回原数组R中
}

void merge_sort(int R[],int start,int end)
{
 	if(start<end)
 	{
  		int mid=(start+end)/2;
  		merge_sort(R,start,mid);	//利用递归实现分解过程
  		merge_sort(R,mid+1,end);
  		merge(R,start,mid,end);
 	}
} 
分析总结

归并排序和快速排序都是分治思想应用在排序中的经典实例,所谓分治即“分而治之”,就是将一个大问题分解成若干小问题,并且小问题要具有和大问题一样的性质,然后将小问题的解合并得到大问题的解。本例中每次归并操作都是将两个子文件合并成一个有序文件,这种方法称为“二路归并排序”。类似地也可以有“三路归并排序”或“多路归并排序”。

利用了分治思想,所以归并排序的效率也是比较高的,利用递归需进行( l o g 2 n log_2n log2n)趟归并,每趟归并花费时间是O( n n n),所以归并排序最好和最坏情况下的时间复杂度均是O( n l o g 2 n nlog _2n nlog2n)。

平均时间复杂度O( n l o g 2 n nlog _2n nlog2n)
空间复杂度O( n n n)

二路归并排序是稳定的。

写在最后

代码的表达形式多种多样,重点是理解排序的思想和过程,附上一个网上看到的动画,可以帮助理解排序过程☛添加链接描述(个人觉得如果有一些基础的看本文上面给的图示去理解最好,更有助于建立编程的思维,视频能相对有些趣味性)
说明: 链接内视频不是本人制作,如侵权则删。当然网上的视频有很多,我只是找了一个相对简单明了的,大家也可自行搜索。

参考资料:《数据结构-用C语言描述》高等教育出版社

(只是分享个人学习时的想法和理解,如有问题还望大佬指点)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

#include编程小黑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值