遞迴到非遞迴轉換 歸併排序與快排的非遞迴實現

2021-05-28 04:39:53 字數 3086 閱讀 4203

在高階語言中,函式的引數傳遞是由棧來實現的,後呼叫的函式的引數在棧的上部,先呼叫的函式的引數在棧的下部,在實現遞迴函式時,每一次呼叫的引數等資訊都會儲存在棧中,這樣在資料比較在時會出現棧溢位的錯誤,而且反覆呼叫函式,會使效率變的較低,在vc中對10萬個數排序,用遞迴的快排花了30ms,而用非遞迴,需要25ms。

而我們可以很容易的通過使用自定義的棧,來將其轉化為全部在乙個函式中實現,而無需進行遞迴函式呼叫,從而節省了大量時間,而且也可以盡量避免棧舉出的問題。

遞迴函式一般有兩類,一類是先執行函式操作,再遞迴呼叫函式自身,一類是先遞迴呼叫自身,再執行函式操作,題目所述的兩種排序分別屬於兩種遞迴呼叫。

先說快速排序,首先將它的遞迴版本給出,每次以最後乙個元素為標準,將比它小的元素全部換到前面去,然後把最後乙個元素換到最後乙個比它小的元素後面,從而實現該元素左面的元素都比它小,而右面的都比它大:

void ksort(int l,int h,int a)//l為第乙個元素下標 h為最後乙個元素下標的後乙個

int i,j=l;

int tem;

if(l>=h)return;

for(i=l;iif(a[i]tem=a[i];

a[i]=a[j];

a[j]=tem;

j++;

tem=a[j];//最後將a[h-1]搬到中間去,讓不比它小的都在它右面

a[j]=a[h-1];

a[h-1]=tem;

ksort(l,j,a);///遞迴

ksort(j+1,h,a);

要模擬該遞迴過程 , 首先要做的就是建立乙個棧 , 最簡單的方法是用陣列 , 建立兩個陣列模擬的棧 sl[100],sh[100] 分別存放 引數中的每次操作的首元素的位置和尾元素的後乙個位置  ,定義變數head表示棧頂指標,

首先將sl[0] 和 sh[0] 分別賦值為 l 和 h , 對於先執行後遞迴的函式,在每次執行遞迴的時候 , 將新的引數壓入棧中, 然後在入棧之後重新執行新一輪的函式操作, 因為重複執行同樣的動作, 所以需要乙個迴圈 ,每個取引數, head 要自減, 所以跳出條件就是head<0:

while(head>=0)

x=sl[head];

y=sh[head];

head--;

j=x;

for(i=x;iif(a[i]tem=a[i];

a[i]=a[j];

a[j]=tem;

j++;

tem=a[j];

a[j]=a[y-1];

a[y-1]=tem;

if(xhead++;

sl[head]=x;

sh[head]=j;

if(j+1head++;

sl[head]=j+1;

sh[head]=y;

類似快速排序這類遞迴呼叫的特點是取一次引數執行一次操作,之後這組引數就沒有用了,可以被下一組引數所覆蓋了,從而不需要很將所有的引數都儲存在棧中,再集中進行處理,而歸併排序這樣的先遞迴,後操作的,則不可以了,下面是歸併排序的遞迴版**:

void mergesort(int a,int l,int h)///此中的h為最後乙個元素的位置

if(l>=h)return ;

int m=(l+h)/2;

mergesort(a,l,m);

mergesort(a,m+1,h);經過這兩行,l到m和m=1到h,就都是已經有序的序列了,然後//將兩個有序序列進行歸併

int *arr=new int[h-l+1];

int k=0;

int i=l,j=m+1;

while(i<=m&&j<=h)

if(a[i]arr[k]=a[i];

i++;

k++;

else

arr[k]=a[j];

j++;

k++;

if(i<=m)

while(i<=m)

arr[k]=a[i];

i++;k++;

if(j<=h)

while(j<=h)

arr[k]=a[j];

j++;k++;

for(i=l;i<=h;i++)

a[i]=arr[i-l];

deletearr;

可見,它需要先進行遞迴,條件成立的話,繼續遞迴,直到條件不成立,則返回,最後一層遞迴呼叫的函式返回之後才會執行下面歸併的操作,所以要先將所有歸併操作中要用到的引數都儲存起來,最後再一層一層進行歸併,儲存引數的過程即為將所有的引數入棧,

而每次新入棧的引數決定於之前的引數,因為歸併排序是分治解決問題的

while(head1<=head)head1表示用來決定新引數的引數在棧中的位置,head為新引數的///位置

x=sl[head1];

y=sh[head1];

head1++;

m=(x+y)/2;

if(xhead++;

sl[head]=x;

sh[head]=m;

if(m+1head++;

sl[head]=m+1;

sh[head]=y;

棧建好之後,就可以在棧中從頂至底取引數,進行歸併了

while(head>=0)

x=sl[head];

y=sh[head];

head--;

m=(x+y)/2;

int *arr=new int[y-x+1];

i=x,j=m+1,k=0;

while(i<=m&&j<=y)

if(a[i]arr[k]=a[i];

i++;

k++;

else

arr[k]=a[j];

j++;

k++;

if(i<=m)

while(i<=m)

arr[k]=a[i];

i++;k++;

if(j<=y)

while(j<=y)

arr[k]=a[j];

k++;j++;

for(i=x;i<=y;i++)

a[i]=arr[i-x];

deletearr;

以上為個人學習總結, 歡迎reader們提出寶貴建議與指導~

歸併排序(遞迴與非遞迴)

1.遞迴 把序列分成元素個數盡量相等的兩部分,再將兩半分別排序,合併有序的兩個序列 遞迴 void merge sort int a,int low,int heigh,int t a為待排序陣列,low,high分別為a的上下限 0 n 1 t為輔助陣列 for i low,j 0 i heigh...

快排和歸併排序的非遞迴實現

快速排序 是一種交換排序,當完全有序時退化為氣泡排序,時間複雜度為o n 2 正常情況下為o nlogn 非遞迴 其實就是手動利用棧來儲存每次劃分後兩個序列的起始點和終止點。棧非空時獲取棧頂兩個值 起始點和終止點,然後再根據兩個點劃分獲得中軸,將兩個序列中沒劃分完的起始點和終止點入棧。重複這個過程,...

歸併排序 遞迴 非遞迴

首先簡單的介紹一下歸併演算法的核心思想 將我們將一組資料分成若干個組,即分到每組資料為1個元素的情況下就不用分了,然後在分別比較每兩組資料元素的大小,將其合併為一組資料再去和其他同等級別的組的資料元素取比較,然後合併到臨時的空間中然後在複製給原空間,依此類推,直到最後全部合併完畢,陣列就成為一組有序...