1. 程式人生 > >歸併排序非遞迴演算法最通俗易懂的解析

歸併排序非遞迴演算法最通俗易懂的解析

分析:

非遞迴,即迭代,與遞迴最大的區別在於實現的方向不同。遞迴拆開來是“遞推”與“迴歸”,也就是先從頂層往下,逐層遞推到底層,再從底層逐層迴歸到頂層,所以mergesort的遞迴版本是先從頂層開始往下不斷對陣列一分為二,到底層歸併,回到上一層,再歸併,重複直到頂層。非遞迴是從底層開始不斷往上迭代,mergesort的迭代版本是從底層開始,對左邊k個右邊k個元素歸併,換下一段,再對左右兩邊k個元素區域性歸併,直到陣列末尾,如果有剩餘,最後再歸併左邊k個和右邊剩餘的元素一次,k乘以2,這樣算一次迭代,下一次遍歷陣列,對2k個元素區域性歸併,直到nk不小於陣列長度,到達頂層,結束。

程式碼:

#include<iostream>
#include<cstdlib>
#define SIZE 30
#define RANDOM 100
using namespace std;
int *b=new int[SIZE];//開頭先定義臨時陣列 
void MergeNonRec(int *elem,int lo,int mi,int hi)
{//對elem陣列的[lo,mi),[mi,hi)部分合並,注意右邊是開區間 
	int lb=mi-lo;
	int lc=hi-mi;
	int *a=elem+lo;//a從elem的lo開始改變elem 
	int *c=elem+mi;//c從elem+mi開始到elem+hi的部分將與elem+lo到elem+mi作對比 
	for(int i=0;i<lb;b[i]=a[i++]);//b接收elem+lo到elem+mi的部分與c對比 
	for(int i=0,j=0,k=0;j<lb||k<lc;)//b與c對比完存入a 
	{
		if(j<lb&&(lc<=k||b[j]<c[k]))a[i++]=b[j++];
		if(k<lc&&(lb<=j||c[k]<=b[j]))a[i++]=c[k++];
	}
}
void MergePass(int *elem,int k,int len)
{
	int i=0;
	while(i+2*k<=len)//遍歷陣列 
	{
		MergeNonRec(elem,i,i+k,i+2*k);//每次對左邊k個和右邊k個元素歸併
		i+=2*k;//合併完兩個k個元素的部分後,指標位移2k個單位 
	}
	if(i+k<=len)//若有剩餘資料則將剩餘部分再歸併一次,即左邊k個右邊len-i-k個 
	MergeNonRec(elem,i,i+k,len);
}
void MergeSortNonRec(int *elem,int len)
{
	int k=1;//定義步長,即合併元素個數 
	while(k<len)
	{
		MergePass(elem,k,len);//遍歷陣列並區域性歸併k個元素,即左邊k個右邊k個 
		k*=2;//兩端的k個元素歸併完,再對兩端2k個元素歸併 
	}
}
int main()
{
	srand(time(NULL));
	int a[SIZE];
	for(int i=0;i<SIZE;i++)
	a[i]=rand()%RANDOM;
	cout<<"Before:\n";
	cout<<a[0];
	for(int i=1;i<SIZE;i++)
	cout<<' '<<a[i];
	MergeSortNonRec(a,SIZE);
	cout<<"\nAfter:\n";
	cout<<a[0];
	for(int i=1;i<SIZE;i++)
	cout<<' '<<a[i];
	cout<<endl;
	return 0;
}