歸併排序非遞迴演算法最通俗易懂的解析
阿新 • • 發佈:2018-12-31
分析:
非遞迴,即迭代,與遞迴最大的區別在於實現的方向不同。遞迴拆開來是“遞推”與“迴歸”,也就是先從頂層往下,逐層遞推到底層,再從底層逐層迴歸到頂層,所以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; }