遞迴和消去遞迴

2022-03-20 12:54:48 字數 1876 閱讀 1739

儘管遞迴程式在執行時間上往往比非遞迴程式要付出更多,但有很多問題的數學模型或演算法設計方法本來就是遞迴的,用遞迴過程來描述它們不僅非常自然,而且證明該演算法的正確性也比相應的非遞迴形式容易得多,因此遞迴不失為是一種強有力的程式設計方法。

下面來舉個例子:已知元素x,判斷x是否在a(1:n)中。

演算法思想:在a(1:n)中檢索x,若存在,返回該元素在a中的下標,否則,返回0。

解決這一問題的遞迴演算法可描述如下:

演算法4.3 在陣列a(1:n)中檢索x是否存在

int void search(int a,int i,int x) //search

為了確定x是否在a(l:n)中,應首先在主程式中呼叫search(1)。

當然該問題也可用迭代形式來描述,但使用遞迴時就無需使用迴圈語句了。

在演算法設計的初期階段使用遞迴,一旦所設計的遞迴演算法被證明為正確且確信是乙個好演算法時,就可以消去遞迴,把該演算法翻譯成與之等價的、只使用迭代的演算法。

下面就介紹將直接遞迴過程翻譯成只使用迭代過程的一組規則。對於間接遞迴過程的處理只需把這組規則作適當修改即可。

1. 在過程的開始部分,插人說明為棧的**並將其初始化為空。

使用棧來儲存遞迴過程中的斷點資訊。斷點資訊包括如下幾個內容:

① 呼叫的引數; ② 區域性變數;

③ 呼叫的中間結果(函式的值) ④ 返回位址

2. 將標號l1附於第一條可執行語句。然後,對於每一處遞迴呼叫都用一組執行下列規則的指令來代替。

3. 將所有引數和區域性變數的值存入棧。棧頂指標設計成乙個全程變數。

4. 建立第i個新標號li,並將i存入棧。該標號的i值將用來計算返回位址,該標號用在規則7所描述的程式段中。

5. 計算這次呼叫的各實在引數(可能是表示式)的值,並把這些值賦給相應的形式引數。

6. 插入一條無條件轉向語句轉向過程的開始部分,實現迴圈。

7. 若是函式過程,則對遞迴過程中含有此次函式呼叫的語句作如下處理:

① 將該語句的此次函式呼叫部分用從棧頂取回該函式值的**來代替;

② 其餘部分的**按原描述方式照抄;

③ 將規則4中所建立的標號附於這條語句上。

若此過程不是函式,則將4中建立的標號附於規則6所產生的轉移語句後面的那條語句上。

以上步驟是消去過程中的所有遞迴呼叫,此外,還需要對遞迴過程中的return語句進行處理。注意純過程結束處的end需看成一條沒有返回值的return語句。

在每個有return語句的地方,執行下述規則:

8. 如果棧為空,則執行正常返回。

9. 否則,將所有輸出引數(即理解為 out 或 inout 型的引數)的當前值賦給棧頂上的那些對應的變數。

10. 如果棧中有返回位址標號的下標,就插入一條此下標從棧中退出的**,並把這個下標值賦給乙個未使用的變數。

11. 從棧中退出所有區域性變數和引數的值並把它們賦給對應的變數。

12. 如果這個過程是函式,則插人以下指令,這些指令用來計算緊接在return後面的表示式並將結果值存入棧頂。

13. 用返回位址標號的下標實現對該標號的轉向。

在一般情況下,使用上述規則都可將乙個直接遞迴過程正確地翻譯成與之等價的只使用迭代的過程。它的效率通常比原遞迴模型要高,進一步簡化這程式可使效率再次改進。

演算法4.4 遞迴求取最大值

int void max1(int i)

else

k=n;

return k ;

}//max1

用幾個簡單的資料實驗一下這個演算法,就會明白該演算法是個遞迴模型。在執行時間上,由於過程呼叫和隱式棧管理方面的消費,使我們自然考慮到要消去歸。

演算法4.5是與演算法4.4等價的迭代演算法

int void max2(int i)//i

遞迴和尾遞迴

c語言中編譯預處理的三種形式的命令 巨集定義,檔案包含,條件編譯命令。1 巨集定義主要是 define,undef 如下 define pi 3.1415926 不帶引數的巨集定義 define max a,b a b?a b 帶引數的巨集定義 說明 巨集定義在c語言與c 語言中是相通的。下面舉例說...

遞迴和非遞迴

1 遞迴就是函式呼叫函式本身,執行起來就是函式巢狀函式,層層巢狀,所以函式呼叫 引數堆疊都是不小的開銷,但是程式簡單。2 非遞迴就是不斷地對引數入棧 出棧,省去了函式層層展開 層層呼叫的開銷。雖然引數出入棧次數多了,但是一般都開闢固定的足夠大的記憶體來一次性開闢 重複使用。3 非遞迴是從堆疊的角度來...

遞迴函式 頭遞迴和尾遞迴

學習總結自 像程式設計師一樣思考 v.anton spraul 著,徐波 譯 遞迴,也就是乙個函式直接或間接呼叫自身。一般來說,遞迴可以分為直接遞迴和間接遞迴。直接遞迴,是指函式自己呼叫自己的情況,而間接遞迴,是指呼叫其他函式時,在其他函式中又呼叫了自己的情況。現在,主要將遞迴分為頭遞迴和尾遞迴來學...