遞迴與迭代

2022-01-13 02:04:13 字數 2506 閱讀 2984

首先考慮下面的階乘函式:

然後注意到1!等於1,就可以翻譯出如下的**:

int factorial(int

n)

return n * factorial(n -1

);}

多麼的簡潔明瞭,對於factorial(4)可以寫出下面的遞迴過程

factorial(4)

4*factorial(3)

4*3*factorial(2)

4*3*2*factorial(1)

4*3*2*1

4*3*2

4*6

24 下面換一種思路計算階乘,可以將計算階乘n!的規則描述為:

先將1和2相乘,結果儲存起來計為product,再和3相乘,然後一直乘到n。可以看出這裡面包含乙個

從1到n的計數器counter

這一計算過程可以描述如下:

counter *product -> product

counter + 1 -> counter

n!也就是計數器counter超過n時乘積product的值。

可以描述為下面的**:

int fact(int

n)

int fact_iter(int product, int cnt, int

max_cnt)

return fact_iter(cnt*product, cnt + 1

, max_cnt);

}

對於fact(4)可以寫出下面的迭代過程

fact (4)

fact_iter (1, 1, 4)

fact_iter (1, 2, 4)

fact_iter (2, 3, 4)

fact_iter (6, 4, 4)

fact_iter (24, 5, 4)

24 現在來對兩個計算過程做乙個比較,從運算的步驟來看,兩種所需要的步驟數目都是正比於n的,但從另一方面,如果我們考慮兩個計算過程的"形狀"就會發現他們的進展情況就會大不一樣!

在第乙個計算過程的"形狀"呈先逐步展開而後收縮。在展開階段裡,構造起乙個推遲進行的操作所形成的鏈條,收縮階段表現為這些運算子的實際執行。這種型別的計算過程由乙個推遲執行的鏈條刻畫,稱為乙個遞迴計算過程。要執行這種過程,編譯器就需要維護好那些以後將要執行的操作的軌跡。而這個儲存的資訊量與n成線性關係,所以該過程是線性遞迴過程

與之相對應,第二個計算過程裡並沒有任何增長和收縮,對於任何乙個n,在計算過程中的每一步,在我們所有需要儲存的軌跡裡,所以的東西就是變數product,cnt,max_cnt的當前值。我們稱這一過程為乙個迭代計算過程。所需的計算步驟隨著n線性增長,這種過程稱為線性迭代過程。一般來所迭代計算過程就是那種其狀態可以用固定數目的狀態變數描述的計算過程,而與此同時,又存在著一套固定的規則,描述了計算過程從乙個狀態到下一狀態轉換時,這些變數的更新方式;還有乙個結束檢測,它描述著一計算過程應該終止的條件

我們還可以從另乙個角度來看這兩個過程之間的對比。在迭代的情況裡,在計算過程中的任何一點,那幾個程式變數都提供了有關計算狀態的乙個完整描述。如果我們令上述計算在某兩步之間停下來,要想重新喚醒這一計算,只需為直譯器提供有關這三個變數的值。而對於遞迴計算過程而言,這裡還存在著另外的一些隱含資訊,它們並未儲存在程式變數裡,而是由直譯器維持著,指明了在所推遲的運算所形成的鏈條裡的漫遊中,"這一計算過程處在何處"。這個鏈條越長,需要儲存的資訊也就越多。

在做迭代與遞迴之間的比較時,我們必須小心,不要搞混了遞迴計算過程的概念和遞迴過程的概念。當我們說乙個過程是遞迴的時候,論述的是乙個語法形式上的事實,說明這個過程的定義中(直接或間接地)引用了該過程本身。在說某一計算過程具有某種模式時(如線性遞迴),我們說的是這一計算過程的進展方式,而不是相應過程書寫上的語法形式。

現在再來個斐波那契數列的例子。定義如下:

(n>=2)

可以輕鬆寫出前幾項0 1 1 2 3 5 8 13 … (特別指出:0不是第一項,而是第零項。)

根據定義很快就可以翻譯成如下**

int fib(int n)

if(n == 1)

return fib(n-1) + fib(n - 2);

} 很明顯上面是遞迴的過程。上乙個狀態可以推導出下乙個狀態,但是下乙個狀態的值又影響到上乙個狀態。

再來考慮怎麼用迭代計算,用一對整數a和b,將他們分別初始化為fib(1) = 1, fib(0) = 0, 反覆的使用下面的變換規則:

a+b -> a

a -> b

下面是迭代版本的**:

int fib_iter(int a, int b,int

cnt)

return fib_iter(a+b, a, cnt - 1);}

int fib(int

n)

注:本文中的例子來之《電腦程式的構造和解釋》

遞迴與迭代

遞迴與迭代都是基於控制結構 迭代用重複結構,而遞迴用選擇結構。遞迴與迭代都涉及重複 迭代顯式使用重複結構,而遞迴通過重複函式呼叫實現重複。遞迴與迭代都涉及終止測試 迭代在迴圈條件失敗時終止,遞迴在遇到基本情況時終止。使用計數器控制重複的迭代和遞迴都逐漸到達終止點 迭代一直修改計數器,直到計數器值使迴...

遞迴與迭代

1 遞迴 當函式用自身來定義時就稱為是遞迴 recursive 的。遞迴必須滿足四個基本法則 1 基本情形 必須給出基準情況,不用遞迴就能求出,用於終止遞迴運算 2 不斷推進 對於那些要被遞迴求解的情形,遞迴呼叫必須能夠朝著乙個基準情形推進 3 設計法則 假設所有的遞迴呼叫都能執行 4 合成效益法則...

遞迴與迭代

遞迴是什麼?簡單來說,就是函式自己調自己的一種方法。通常可以把乙個大型複雜的問題轉化為乙個與原問題相似的規模較小的問題來求解。遞迴的兩個必要條件 以下用幾個例項來說明 題目一 接受乙個無符號整數,把它轉化為字元並列印它。void print int n printf d n 10 int main ...