【模板】归并排序

归并排序基本思想

二分法、分治法、递归思想。

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

归并排序基本流程

说法1.按照二分思想,先将序列分成两个大小大致相同的2个子集合,分别对2个子集合进行排序(段内有序),最终将排好序的子集合合并成为所要求的排好序的集合(段间有序)。

说法2.从整体来看,假设初始序列有n个元素,实际是将它看成n个有序的子序列(长度是1),然后两两归并,直到得到长度是n的有序子序列。

时间复杂度分析:平均时间复杂度得出是o(nlogn),是渐近意义下的最优排序算法。原因:考虑两两归并的过程,每一层进行n次比较,归并树的高度是log_2n,因此得解。

空间复杂度分析:

在合并有序数组时需要额外的辅助空间,递归也要调用栈的空间,整体复杂度o(n)

稳定性分析:是稳定的排序(相同元素相对位置不变)。

如图是代码所示的2路-归并排序(同理可以有3路、4路)。

图片来源

代码注意点

1.写递归程序要注意写结束条件(if(low>=high))。

2.合并时必须申请新的存储空间,不可以在原始数组上操作。

3.for循环后还可能有没有合并的元素,需要while循环直接合并剩下的元素。

//归并排序
#include<iostream>
#include<cstring>
#include<cstdlib>
using namespace std;
void merge(int a[],int low,int mid,int high)
 //合并a[low...mid]和a[mid+1...high] (有序) 
 {
 	int *tmp = new int[high-low+1];	//动态分配临时空间 
 	int i,j,k;//临时变量 
	 for(i=low,j=mid+1,k=0;i<=mid && j<=high;k++)
	 //注意循环条件,当有一边的元素合并完成后即不满足循环条件 
	 {
	 	if(a[i]<a[j])
	 	{
	 		tmp[k]=a[i];
	 		i++;
		 }
		 else{
		 	tmp[k]=a[j];
		 	j++;
		 }
	 }
	 while(i<=mid)//归并可能存在的剩余元素(左) 
	 {
	 	tmp[k]=a[i];
	 	k++;i++;
	  } 
	  while(j<=high)//归并可能存在的剩余元素(右) 
	  {
	  	tmp[k]=a[j];
	  	k++;j++;
	  }
 	for(int i=0;i<k;i++)
 	{
 		a[low+i]=tmp[i]; 
		 //把临时数组的元素存回原始数组
	 }
	 delete []tmp;//释放临时空间 
  } 
void mergeSort(int a[],int low,int high)
{
	if(low>=high) return; //当只有一个元素时返回 
	if(low<high)
	{
		int mid = (low+high)/2;
		mergeSort(a,low,mid);	//二分法 
		mergeSort(a,mid+1,high);	//递归调用 
		merge(a,low,mid,high);//合并有序序列 
	}
 } 
  int main(void)
{
	int n = 10;
	int arr[10] = {0};
	for(int i=0;i<n;i++)
	{
		arr[i]=rand()%100;
	}
	for(int i=0;i<n;i++)
	{
		cout<<arr[i]<<" ";
	}
	cout<<endl; 
	mergeSort(arr,0,n-1);
	for(int i=0;i<n;i++)
	{
		cout<<arr[i]<<" ";
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值