归并排序及其时间复杂度、代码(c++实现)、改进和应用场景

归并排序是一种稳定的非线性排序算法,通过分治法将数组分为两部分,分别排序后合并。其时间复杂度为O(nlogn)。在处理大量数据时,可以通过在长度小于一定阈值时切换为其他排序算法来优化。在外排序中,归并排序常用于数据的合并阶段,以创建有序的大文件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

归并排序

基本思想:将数组A[0 … n-1]中的元素分成两个子数组A1[0 … n/2]和A2[n/2+1 … n-1]。分别对这两个子数组单独排序,然后将一排序的两个子数组归并成一个含有n个元素的有序数组。

归并排序包含不相邻元素的比较,但并不会直接交换。在合并两个已排序的数组时,如果遇到了相同的元素,只要保证前半部分数组优先于后半部分数组,相同元素的顺序就不会颠倒,所以归并排序属于稳定的非线性的排序算法

归并排序算法虽然高效且稳定,但在处理过程中除了用于保存输入数据的数组外,还要临时占用一部分的内存空间。

归并排序是个原地的排序,空间可以为O(1)

1、时间复杂度

算法的递推关系
在这里插入图片描述
若n=2k,则有
在这里插入图片描述若2k<n<2k+1,
在这里插入图片描述则时间复杂度为:T(n)=O(nlogn)


2、代码实现

const int maxn=100;
int temp[maxn];
void MergeSort(int *a,int low,int high)
{
	if(low>=high)//代码段①
		return;
	int mid=(low+high)/2;
	MergeSort(a,low,mid);
	MergeSort(a,mid+1,high);
	Merge(a,low,mid,high);
}

void Merge(int *a,int low,int mid,int high)
{
	int i=low;
	int j=mid+1;
	int size=0;
	for(;(i<=mid)&&(j<=high);size++)
	{
		if(a[i]<a[j])
			temp[size]=a[i++];//代码段②
		else
			temp[size]=a[j++];
	}
	while(i<=mid)
		temp[size++]=a[i++];
	while(j<=high)
		temp[size++]=a[j++];
	for(i=0;i<size;i++)
	{
		a[low+i]=temp[i];
	}
}

3、改进

代码段①

if(low>=high)//代码段①
		return;

可以进行改进,当长度<5或者<7,可以换成冒泡排序、选择排序,避免递归深度过大,效率能够提高。

代码段②

for(;(i<=mid)&&(j<=high);size++)
	{
		if(a[i]<a[j])
			temp[size]=a[i++];//代码段②
		else
			temp[size]=a[j++];
	}

temp可以存储数据的索引,而非数据的值,避免数据的值过大的时候拷贝所耗费的时间与空间。

4、应用场景

外排序是指处理超过内存限度的数据的排序算法。通常将中间结果放在读写较慢的外存储器(通常是硬盘)上。

外排序通常采用“排序-归并”策略

  • 排序阶段:读入能放在内存中的数据量,将其排序输出到临时文件,一次进行,将待排序数据组织为多个有序的临时文件。
  • 归并阶段:将这些临时文件组合为大的有序文件。

【举例】
使用100M内存对于900MB的数据进行排序:

  • 读入100M数据内存,用常规方式(如堆排序)排序。
  • 将排序后的数据写入磁盘。
  • 重复前两个步骤,得到9个100MB的块(临时文件)中。
  • 将100M内存划分为10份,前9份中为输入缓冲区,第10份输出缓冲区。
    (如前9份各8M,第10份18M;或10份大小同时为10M)
  • 执行九路归并算法,将结果输出到缓冲区
    (若输出缓冲区满,将数据写至目标文件,清空缓冲区。若输入缓冲区空,读入相应文件的下一份数据)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值