淺析遞迴演算法的執行原理
遞迴,即程式(函式)直接或者間接呼叫自己的一個過程。
遞迴演算法主要有四個特點:
1. 必須有可達到的終止條件,不然程式(函式)將陷入死迴圈(死鎖);
2. 子過程可通過再次遞迴的方式呼叫求解或因滿足終止條件而直接求解;
3. 子過程的規模比原過程小(一般是折半),或更接近終止條件;
4. 所有子過程的解構成整個過程的解的集合。
先來一段程式碼:
下面是分組歸併排序(分治法)的遞迴過程:
在Java環境下執行:
void Mergesort(int arr[],int s,int t) {
int m,r1[]=new int [100]; //假設最多存放100個元素
if (s==t) {
return;
} //必須寫上'return',不然進入死迴圈
else{
m = (s + t) / 2;
Mergesort(arr, s, m); //左邊有序
/*Mergesort(arr, m + 1, t); //右邊有序
Merge(arr, r1, s, m, t); //再將兩個有序數列合併
for(int i=s;i<=t;i++){
arr[i]=r1[i];
System.out.print(arr[i]+" ");
}*/
System.out.print(m);
}
System.out.println();
}
在Main輸入:int arr[]={7,6,3,4,5,2,1} ; Mergesort(arr,0,7);
Console顯示:0
1
3
分析:
首先簡化過程,將無關語句刪減,冗餘語句則用”…”進行省略,方便閱讀。
主過程Mergesort開始執行,判斷if條件不符合後轉入else語句方向,執行語句。
當遇到同名函式
時,後面的語句暫不執行,放入記憶體棧中保留,之後,從頭開始執行。–>需要注意的是,這裡所說的“從頭開始”是相對的,呼叫自身後所含引數是變動的,而新過程的語句和主過程(原過程)完全一致,繼續從上到下重新執行,便有“從頭開始”一說。<–
第二次以後的執行過程跟第一次同理,執行後先判斷條件,後選擇if-else的執行方向。如再次遇到同名函式,則繼續呼叫自身。如此反覆執行,直到遞迴結束為止,這就是所謂的“遞迴”。
為了方便分析,我們把主過程稱為原過程,用M1表示;呼叫自身後執行的過程稱為子過程,以 Mi ( i=2,3,…,n)表示。
要搞清遞迴過程,判斷其入口和出口顯得即為關鍵,而遞迴的終止點,是一個無參值標記,一般為空值。
找出入口、出口和終止點後,不難發現,原來遞迴是這麼一個過程:
void Mergesort(int arr[],int s,int t){ // M1 Starts
int m,r1[]=new int [100]; // 假設最多存放100個元素
if (s==t) {
return;
} // 必須寫上'return',不然進入死迴圈
else{
m = (s + t) / 2;
Mergesort(arr, s, m){ // M2 Starts
... //省略(後面同)
if ... //不執行
else{
m = (s + t) / 2;
Mergesort(arr, s, m){ // M3 Starts
...
if ... //不執行
else{
m = (s + t) / 2;
Mergesort(arr, s, m){ // M4 Starts
...
if (s==t) {
return; } //遞迴終止
else...
... //不執行
System.out.println();
} // M4 Ends
System.out.print(m); // E3 Prints m3
}
System.out.println(); // I3
} // M3 Ends
System.out.print(m); // E2 Prints m2
}
System.out.println(); // I2
} // M2 Ends
System.out.print(m); // E1 Prints m1
}
System.out.println(); // I1
} // M1 Ends
小結:
1. 遞迴是呼叫自身的一種演算法,或是一種過程;
2. 多次遞迴組合而成的整過程更像是一種巢狀了多個自元素(同名函式)的一體化函式;
3. 遞迴執行的語句在遇到同名函式前正常執行,而其後的語句則暫時保留在記憶體中,待其遞迴後得到的
子過程完全結束後才繼續執行。故有規律:越是最前的函式語句,遞迴後越在最後執行。
4. 找出每次遞迴過程的入口、出口以及整個遞迴過程的終止點極為關鍵;
5. 劃分歸併的思想在遞迴演算法中得到了很好的運用,此思想在很多演算法裡都有極為精妙的體現。
如有問題,歡迎指正,謝謝!