归并排序

1、归并排序

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

归并排序主要分为三个步骤

第一, 分解: 把待排序的 n 个元素的序列分解成两个子序列, 每个子序列包括 n/2 个元素. 
第二, 治理: 对每个子序列分别调用归并排序MergeSort, 进行递归操作 
第三, 合并: 合并两个排好序的子序列,生成排序结果. 

首先考虑下如何将将二个有序数列合并。这个非常简单,只要从比较二个数列的第一个数,谁小就先取谁,取了后就在对应数列中删除这个数。然后再进行比较,如果有数列为空,那直接将另一个数列的数据依次取出即可。


2、两个子序列的合并

两个子序列:[left,mid],[mid+1,right],要对这个两个数组进行合并并有序。
思想:同时遍历两个子数组,保存数值小的那个元素,并且取下一个;
当其中一个数组已经遍历完毕时,可以把另一个数组的剩余元素全部保存到临时数组;

void MergeArray(int a[], int left, int mid, int right, int temp[])
{
	int i,j,m,n,k;
	i=left; j=mid+1; k=0;
	m=mid; n=right;
	while(i<=m && j<=n)
	{
		if(a[i]<=a[j]) //保存较小者
			temp[k++]=a[i++];
		else
			temp[k++]=a[j++];
	}
	
	while(i<=m) //当一个数组遍历完毕,需要把另一个数组的剩余元素全部保存到临时数组 
		temp[k++]=a[i++];
	while(j<=n)
		temp[k++]=a[j++];
	
	//Copy temp array to a
	for(i=0;i<k;i++)
		a[left+i]=temp[i];
}

3、对整个数组归并排序

整个归并过程递归对子数组进行归并,排序

void Merge(int a[], int left, int right, int temp[])
{
	if(left<right) //递归条件判断
	{
		int mid=(left+right)/2;
		Merge(a, left, mid, temp); //递归对左子数组排序
		Merge(a, mid+1, right, temp); //递归对右子数组排序
		MergeArray(a,left,mid,right,temp); //合并左子数组和右子数组
	}
}

4、时空复杂度分析


时间复杂度分析:

归并排序时间复杂度公式:


当n=1时可以设T(1)=c 1,当n>1时可以设T(n)=2T(n/2)+c2n
于是上述公式可以转化为:


这样计算出的结果应该是T(n)的上界。下面我们把T(n/2)展开成2T(n/4)+cn/2,然后再把T(n/4)进一步展开,直到最后全部变成T(1)=c1,图示如下:


所有的项加起来就是总的执行时间。这是一个树状结构,每一层的和都是cn,共有logn+1层,因此总的执行时间是cnlogn+cn,相比nlogn来说,cn项可以忽略,因此T(n)的上界是Θ(nlogn)。

如果先前取c1和c2中较小的一个设为c,计算出的结果应该是T(n)的下界,然而推导过程一样,结果也是Θ(nlogn)。既然T(n)的上下界都是Θ(nlogn),显然T(n)就是Θ(nlogn)。

空间复杂度分析:
由于在合并两个子数组的时候,用到了一个临时数组temp,该数组的大小和原始数组a的大小一致,因此
空间复杂度:O(n)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值