归并排序

归并排序(MergeSort)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。





归并排序,它采取分而治之(Divide-and-Conquer)的策略,时间复杂度是O(N*lgN)。

归并排序的步骤如下:

1. Divide: 把长度为n的输入序列分成两个长度为n/2的子序列。

2. Conquer: 对这两个子序列分别采用归并排序。

3. Combine: 将两个排序好的子序列合并成一个最终的排序序列。

在描述归并排序的步骤时又调用了归并排序本身,可见这是一个递归的过程。


下面过程来分析,见下图:




代码实现:

void _MergeSort(int* a,int* tmp,int left,int right)
{
	if(left >= right)
		return;

	int mid=left+((right-left)>>1);
	int begin1=left,end1=mid;
	int begin2=mid+1,end2=right;

	if(left < mid)      //left=mid时,单个元素不进行分割
		_MergeSort(a,tmp,left,mid);

	if(mid < right)
		_MergeSort(a,tmp,mid+1,right);

	int index=left;
	//进行归并
	while(begin1 <= end1 && begin2 <= end2)
	{
		if(a[begin1] < a[begin2])
			tmp[index++]=a[begin1++];

		else
			tmp[index++]=a[begin2++];
	}

	while(begin1 <= end1)   //一段为空,一段不为空的情况单独考虑
	{
		tmp[index++]=a[begin1++];
	}

	while(begin2 <= end2)  
	{
		tmp[index++]=a[begin2++];
	}

	for(int i=left;i<=right;++i)
	{
		a[i]=tmp[i];
	}
}
void MergeSort(int* a,int begin,int end)
{
	assert(a);
	int* tmp=new int[end-begin+1];
	assert(tmp);
	_MergeSort(a,tmp,begin,end);
	delete[] tmp;
}

归并排序算法改进:

可利用插入排序优化归并排序,

在归并中利用插入排序不仅可以减少递归次数,还可以减少内存分配次数(针对于原始版本)。

尽管归并排序最坏情况运行时间为o(nlgn),插入排序的最坏运行时间为o(n^2),但是插入排序的常数因子使得它在n较小时,运行要更快一些。因此,在合并排序算法中,当子问题足够小时(子区间元素个数小于13),采用插入排序就比较合适了。然后,再用标准的合并机制将它们合并起来。

 

void InsertSort(int* arr,size_t sz)
{
	assert(arr);
	for(int index=1;index<sz;++index)  //先默认下标为0的元素有序
	{
		int pos=index-1;
		int tmp=arr[index];
		while(pos>=0 && tmp < arr[pos])
		{
			std::swap(arr[pos],arr[pos+1]);
			--pos;
		}
		arr[pos+1]=tmp;
	}
}
void _MergeSort(int* a,int* tmp,int left,int right)
{
	if(left >= right)
		return;

	int mid=left+((right-left)>>1);
	int begin1=left,end1=mid;
	int begin2=mid+1,end2=right;

	if(left < mid)      //left=mid时,单个元素不进行分割
	{
		if(right-left >13)
			_MergeSort(a,tmp,left,mid);
		else
			InsertSort(a+left,right-left+1);
	}
		
	if(mid+1 < right)     
	{ 
		if(right-mid-1 >13)
			_MergeSort(a,tmp,right,mid);
		else
			InsertSort(a+mid+1,right-mid);   //[mid+1,right]所以元素个数为right-mid
	}

	int index=left;
	//进行归并
	while(begin1 <= end1 && begin2 <= end2)
	{
		if(a[begin1] < a[begin2])
			tmp[index++]=a[begin1++];

		else
			tmp[index++]=a[begin2++];
	}

	while(begin1 <= end1)   //一段为空,一段不为空的情况单独考虑
	{
		tmp[index++]=a[begin1++];
	}

	while(begin2 <= end2)  
	{
		tmp[index++]=a[begin2++];
	}

	for(int i=left;i<=right;++i)
	{
		a[i]=tmp[i];
	}
}
void MergeSort(int* a,int begin,int end)
{
	assert(a);
	int* tmp=new int[end-begin+1];
	assert(tmp);
	_MergeSort(a,tmp,begin,end);
	delete[] tmp;
}


比较排序算法就先介绍到此,下面看一下它们之间的区别:




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值