算法---归并排序(Merge Sort)---多版本对比

归并排序是一种利用“分治”手段来实现的排序方法,其通过二分将数组分为若干个有序的子数组,然后再将这些子数组合并到一起组成一个新的数组。

算法的具体实现:

void sort::merge_sort(int* a, const int low, const int high)
{
	if(low>= high)
		return;
	int mid = (low+high)/2;
	merge_sort(a,low,mid);
	merge_sort(a,mid+1,high);
	merge(a,low,mid,high);
}

上述实现可以看出,此算法通过递归将数组分为若干个有序的小数组,然后再使用merge方法将这些小数组进行合并,从而完成数组的排序。

merge方法的实现

void sort::merge(int*a ,const int low,const int mid, const int high)
{
	if(a[mid]<=a[mid+1])
		return ;
	int* copy_a = new int[high-low+1];
	for(int i=low; i<=high; i++)
		copy_a[i-low] = a[i]; 
	int i=low;
	int j=mid+1;
	for(int k=low; k<=high; k++)
	{
		if(i>mid)
		{
			a[k] = copy_a[j-low];
			j++;
		}
		else if(j>high)
		{
			a[k] = copy_a[i-low];
			i++;
		}
		else if(copy_a[i-low]>copy_a[j-low])
		{
			a[k] = copy_a[j-low];
			j++;
		}
		else
		{
			a[k] = copy_a[i-low];
			i++;
		}
	}
	delete[] copy_a;
}
上述实现可以看出,其实就是将两个有序的数组合并到一个新的数组中而已。

算法的时间复杂度分析,假设有N个数,使用归并排序所需的时间为T(N),则从算法的实现可以看出,对N个数排序,需要先分别对左右两边的N/2个数排序,时间为2T(N/2),然后再将排序的两个数组合并,所需时间为N,因此可得T(N) = 2*T(N/2)+N,计算可得T(N)=NlogN。

上述算法可有改进的地方。显然是有的。

首先,如果使用归并排序来排序较小的数组的话,其算法性能没有之前所说的插入排序好(插入排序算法实现),为此可以设定一个阈值,再使用归并排序的过程中如果子数组的元素个数小于这个阈值时,使用插入排序来对相应的子数组进行排序。

算法实现:

void sort::merge_sort_update1(int* a, const int low, const int high)
{
	if((high-low + 1) < N)
	{
		for(int i=low+1; i<=high; i++)
		{
			int j=i;
			int temp = a[i];
			for(; j>low && temp < a[j-1]; j--)
			{
				a[j] = a[j-1];
			}
			a[j] = temp;
		}
		return;
	}
	int mid = (low + high)/2;
	merge_sort_update1(a,low,mid);
	merge_sort_update1(a,mid+1,high);
	merge(a,low,mid,high);
}
上述算法改进之后性能上比原来的归并排序稍好,但是算法的时间复杂度仍然为O(NlogN)。

能否再进一步改进呢?

观察发现,归并排序始终使用一个备份数组来存储排序后的元素,然后再将排序后的元素复制到原来的数组中。在数组新建的过程中将会花费大量的时间。为此可以在这个方面改进一下。可以使用一个实现建好的数组,然后只需使用赋值运算即可,避免了不必要的数组的新建与删除,从而加快了算法的执行速度。

算法实现:

void sort::merge_sort_update2(int* a, const int low, const int high, int* copy_a)
{
	if(low>=high)
		return;
	int mid = (low+high)/2;
	merge_sort_update2(a,low,mid,copy_a);
	merge_sort_update2(a,mid+1,high,copy_a);
	merge_update2(a,low,mid,high,copy_a);
	for(int i=low; i<=high; i++)
		copy_a[i] = a[i];
}
void sort::merge_update2(int*a ,const int low,const int mid, const int high,const int * copy_a)
{
	if(a[mid] <= a[mid+1])
		return;
	int i=low; 
	int j=mid+1;
	for(int k=low; k<=high; k++)
	{
		if(i>mid)
			a[k] = copy_a[j++];
		else if(j>high)
			a[k] = copy_a[i++];
		else if(copy_a[i] > copy_a[j])
			a[k] = copy_a[j++];
		else
			a[k] = copy_a[i++];
	}
}
上述仅仅是自己在学习归并排序过程中实现的一些想法,如有不足之处还请多多指出,欢迎讨论。




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值