天天看點

歸并排序的遞歸與非遞歸寫法

遞歸的歸并排序很常見,本文在遞歸的基礎上,給出了非遞歸的寫法。

//遞歸的寫法
void Merge(vector<int>& ans, vector<int>& src, int left, int  mid, int right)   //對一個vector中兩個排序好的部分進行合并
{
	int i = left, j = mid+1, k=left;
	while (i<=mid && j<=right)
	{
		ans[k++] = src[i] <= src[j] ? src[i++] : src[j++];
	}

	while (i<=mid) {    ans[k++] = src[i++]; }
	while (j<=right) {    ans[k++] = src[j++];
	}
}

void MergePass(vector<int>& ans, vector<int>& src, int left, int right)
{
	int n = src.size();
	vector<int> v3(n);  //給出n的大小
	if (left == right) ans[left] = src[left];
	else {
	int mid = (right - left)/2 + left;
	MergePass(v3,src,left,mid);
	MergePass(v3,src,mid+1,right);  //将資料存放到v3中
	Merge(ans,v3,left,mid,right);  //将v3中的資料進行合并
	}
}

void MergeSort(vector<int>& ans,vector<int>& src)
{
	int n = src.size();
	MergePass(ans,src,0,n-1);
}
           

//非遞歸的方法

void Merge(vector<int>& ans, vector<int>& src, int left, int  mid, int right)
{
	int i = left, j = mid+1, k=left;
	while (i<=mid && j<=right)
	{
		ans[k++] = src[i] <= src[j] ? src[i++] : src[j++];
	}

	while (i<=mid) {    ans[k++] = src[i++]; }
	while (j<=right) {    ans[k++] = src[j++];
	}
}
void NiceMergePass(vector<int>& ans, vector<int>& src, int n, int s)
{
	int i=0;
	for (i;i+2*s-1<=n-1;i=i+2*s)    //判斷是否滿足2s的大小,若滿足,則可以進行2s大小的合并
	{
		Merge(ans,src,i,i+s-1,i+2*s-1);
	}
	if (i+s <= n-1)  //此步為不夠2s大小,但是大于s,比如s為4,剩下的資料為5,則将4個與一個進行合并
	{
		Merge(ans,src,i,i+s-1,n-1);
	}
	else   //剩下的資料不夠s
	{
		ans[i] = src[i];
		i++;
	}
}

void NiceMergeSort(vector<int>& src)
{
	int n = src.size();
	vector<int> ans(n);
	int s = 1;  //s為進行歸并的大小,從1開始,成倍增長
	while (s<n)  //若s的大小大于vector的長度,則終止
	{
		NiceMergePass(ans,src,n,s);  //将src分别進行兩個s大小的合并,至ans中
		s+=s;
		NiceMergePass(src,ans,n,s);  //将ans分别進行兩個s大小的合并,至src中
		s+=s;
	}
}
           
河漢清且淺,相去複幾許。
           

繼續閱讀