递归实现归并排序(基本排序算法)

归并排序也是一种很有名的排序算法,分而治之的思想。但与同样是分治的快排相比,归并更侧重于“合”,“分”其实是很简单的。

比较重要的一点是归并排序的递归出口问题,当下标left>=right时就不需要再递归了。

归并排序的不太好的一点是空间复杂度有点儿高。前一段百度实习生招聘,有一个算法设计就是对merge函数进行优化,把空间复杂度降为O(1),有好的处理方式请留言。

最常规的实现方式:

#include <iostream>
#include <assert.h>
#define N 20
using namespace std;

//输出数组内容
template <class T>
void print(T arr[],int size)
{
	for(int i=0;i<size;i++)
	{
		cout<<arr[i]<<"  ";
	}
	cout<<endl;
}

//归并排序(递归实现)
template <class T>
void mergeSort(T arr[],T temp[],int left,int right)
{
	//l为数组最左侧下标,r为最右侧下标,m为中间位置下标
	int l=left,r=right,m=(left+right)/2;

	//递归出口
	if(l>=r)
	{
		return;
	}

	//对左字串和右字串分别进行递归排序
	mergeSort(arr,temp,l,m);
	mergeSort(arr,temp,m+1,r);

	//对两个字串进行归并
	merge(arr,temp,l,m,r);
}

//归并函数
template <class T>
void merge(T arr[],T temp[],int left,int middle,int right)
{
	//下标left到middle是左字串,下标middle+1到right是右字串
	int l=left,m=middle,r=right;
	
	//注意别犯i=0,j=0等的脑残错误,第一次写的时候竟然这样写了
	//这个归并函数需要多次调用,所以下标未必是从0开始
	int i=l,j=m+1,k=l;

	//比较两个字串的元素值,把较小的放进temp数组中
	while(i<=m && j<=r)
	{
		//if(arr[i]<=arr[j])
		//{
		//	temp[k++]=arr[i++];
		//}
		//else
		//{
		//	temp[k++]=arr[j++];			
		//}

		//使用三元运算符的简洁写法
		temp[k++]=((arr[i]<arr[j])?arr[i++]:arr[j++]);
	}

	//if(i>m)
	//{
	//	while(j<=r)
	//	{
	//		temp[k++]=arr[j++];
	//	}
	//}
	//else
	//{
	//	while(i<=m)
	//	{
	//		temp[k++]=arr[i++];
	//	}
	//}

	//其实无需判定i和m的关系,使用两个while循环即可(尽管只会执行一个)
	while(j<=r)
	{
		temp[k++]=arr[j++];
	}
	while(i<=m)
	{
		temp[k++]=arr[i++];
	}

	//最后把temp数组值赋给arr数组
	for(i=l;i<=r;i++)
	{
		arr[i]=temp[i];
	}
}

int main()
{
	//int arr[N]={5,4,10,3,9};
	//int arr[N]={5,4,0,3,9,22,7,22,0,-10};
	int arr[N]={5,4,1,3,9,12,7,22,0,-10,12,33,-22,0,88,123,-45,345,-98,-666};
	int temp[N];	//额外开辟的数组

	cout<<"排序前:"<<endl;
	print(arr,N);

	mergeSort(arr,temp,0,N-1);

	cout<<"排序后:"<<endl;
	print(arr,N);

	return 0;
}

欢迎留言讨论对该算法进行优化。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章