遞歸實現歸併排序(基本排序算法)

歸併排序也是一種很有名的排序算法,分而治之的思想。但與同樣是分治的快排相比,歸併更側重於“合”,“分”其實是很簡單的。

比較重要的一點是歸併排序的遞歸出口問題,當下標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;
}

歡迎留言討論對該算法進行優化。



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