遞迴的理解 二

2021-08-18 07:33:14 字數 2670 閱讀 1365

迭代的是人,遞迴的是神;

在初學遞迴的時候, 看到乙個遞迴實現,我們總是難免陷入不停的回溯驗證之中, 因為回溯就像反過來思考迭代, 這是我們習慣的思維方式, 但是實際上遞迴不需要這樣來驗證.

我們怎麼判斷這個階乘的遞迴計算是否是正確的呢? 先別說測試, 我說我們讀**的時候怎麼判斷呢?

思考方式1:回溯的思考方式是這麼驗證的, 比如當n = 4時, 那麼factoria(4)等於4 *factoria(3), 而factoria(3)等於3 *factoria(2), factoria(2)等於2 * factoria(1), 等於2 * 1, 所以factoria(4)等於4 * 3 * 2 * 1. 這個結果正好等於階乘4的迭代定義.用回溯的方式思考雖然可以驗證當n = 某個較小數值是否正確, 但是其實無益於理解.

思考方式2

當n=0, 1的時候, 結果正確.

假設函式對於n是正確的, 函式對n+1結果也正確.

如果這兩點是成立的,我們知道這個函式對於所有可能的n都是正確的。

這種方法很像數學歸納法, 也是遞迴正確的思考方式, 事實上, 階乘的遞迴表達方式就是1!=1,n!=(n-1)!×n;當程式實現符合演算法描述的時候, 程式自然對了, 假如還不對,那是演算法本身錯了…… 相對來說, n,n+1的情況為通用情況, 雖然比較複雜, 但是還能理解,最重要的, 也是最容易被新手忽略的問題在於第1點,也就是基本用例(base case)要對.比如, 上例中, 我們去掉if n <= 1的判斷後, **會進入死迴圈, 永遠不會結束.

1.    怎樣找到乙個問題的遞迴演算法:

(1)  必須要示範如何解決問題的一般情況,通過將問題切分成有限小並更小的子問題.

(2)必須要示範如何通過有限的步驟, 來解決最小的問題(基本用例).

如果這兩件事完成了, 那問題就解決了. 因為遞迴每次都將問題變得更小,而乙個有限的問題終究會被解決的, 而最小的問題僅需幾個有限的步驟就能解決.

漢諾塔的遞迴實現:

電腦科學的新學生通常難以理解遞迴程式設計的概念。遞迴思想之所以困難,原因在於它非常像是迴圈推理;它也不是乙個直觀的過程;當我們指揮別人做事的時候,我們極少會遞迴地指揮他們。

停止的位置稱為:基線條件(base case)基線條件是遞迴程式的最底層位置,在此位置時沒有必要再進行操作,可以直接返回乙個結果所有遞迴程式都必須至少擁有乙個基線條件,而且 必須確保它們最終會達到某個基線條件;

使用歸納定義:

有時候,編寫遞迴程式時難以獲得更簡單的子問題;不過,使用歸納定義的資料集 可以令子問題的獲得更為簡單; 使用歸納資料編寫遞迴過程非常簡單。注意,與我們的遞迴程式非常類似,鍊錶的定義也包括乙個基線條件 — 在這裡是 null 指標由於 null 指標會結束乙個鍊錶,所以我們也可以使用 null 指標條件作為基於鍊錶的很多遞迴程式的基線條件

1.對於遞迴函式的使用,人們所關心的乙個問題是棧空間的增長。確實,隨著被呼叫次數的增加,某些種類的遞迴函式會線性地增加棧空間的使用 —— 不過,有一類函式,即尾部遞迴函式,不管遞迴有多深,棧的大小都保持不變。尾遞迴屬於線性遞迴,更準確的說是線性遞迴的子集。

2.函式所做的最後一件事情是乙個函式呼叫(遞迴的或者非遞迴的),這被稱為尾部呼叫;使用尾部呼叫的遞迴稱為尾部遞迴。

3.當編譯器檢測到乙個函式呼叫是尾遞迴的時候,它就覆蓋當前的活動記錄而不是在棧中去建立乙個新的。編譯器可以做到這點,因為遞迴呼叫是當前活躍期內最後一條待執行的語句,於是當這個呼叫返回時棧幀中並沒有其他事情可做,因此也就沒有儲存棧幀的必要了。通過覆蓋當前的棧幀而不是在其之上重新新增乙個,這樣所使用的棧空間就大大縮減了,這使得實際的執行效率會變得更高。

4.要使呼叫成為真正的尾部呼叫,在尾部呼叫函式返回之前,對其結果不能執行任何其他操作;由於在函式中不再做任何事情,那個函式的實際的棧結構也就不需要了;

(1)  函式在尾部被呼叫之後,還需要使用哪個本地變數?哪個也不需要;

(2)  會對返回的值進行什麼處理?什麼處理也沒有;

(3)  傳遞到函式的哪個引數將會被使用?哪個都沒有。  

遞迴的理解

對於遞迴問題,一定要明確的一點是,初始呼叫該函式時的輸入是什麼樣的 遞迴能夠奏效的前提是,問題的規模一定是減少的,或者更為嚴謹地說,問題一定是朝著遞迴結束的條件執行的 遞迴函式的第乙個要執行的就是 if 判斷,也即每進入一次遞迴,都要首先判斷是否到達遞迴的結束,n 0 其次還要明晰遞迴函式的功能,是...

遞迴的理解

本篇文章只要是實現最大公倍數的遞迴實現方法。最大公倍數是指兩個數能夠被一組數同時整除,其中最大的那個數就叫做最大公倍數,求解最大公倍數這裡主要說兩個想法,其實就是將複雜的問題簡化逐步簡化到乙個很小的問題,然後求得答案。假設有兩個數 252和105 252 21 12 105 21 5 252 105...

遞迴的理解

先考慮第一步,在考慮第二步,第二步可能與第一部的解法思路相同,範圍卻小了 然後一直分解。直到邊界有返回值 特例 下面是個關於遞迴呼叫簡單但是很能說明問題的例子 cpp view plain copy 遞迴例子 include void up and down int int main void vo...