首页 > 学院 > 开发设计 > 正文

Iterative Method / Recursive Method

2019-11-06 06:37:40
字体:
来源:转载
供稿:网友

Iterative Method

「疊代法」。以確定的部分作為起始點,循序漸進推演,最後求得答案。

「疊代法」也會有無窮無盡的情況,例如以試除法建立質數,質數是越建越多;又例如微積分所學的牛頓法,遇到曲線時,小數位數是越算越多。

寫程式時經常以迴圈來實作。因為迴圈事實上也可以用遞迴來完成,所以讀者也可以利用遞迴來實作,只不過我想大家沒必要這麼無聊。

Recursive Method

「遞歸法」。找出一套縮小問題範疇的規律,以此不斷縮小問題,直到能釐清細節,便可歸納答案。

「遞歸法」也會有無窮無盡的情況,例如碎形是越分越細緻。

寫程式時主要以遞迴來實作。因為遞迴也可以用stack 和迴圈來完成,所以讀者也可以利用迴圈來實作,只不過我想大家沒必要這麼累。

UVa 10994 10212 10471 10922

比較 Iterative Method 與 Recursive Method

Iterative Method 與 Recursive Method 有種對立的味道: Iterative Method 是針對已知,逐步累積,直至周全; Recursive 是針對未知,反覆拆解,直至精細。

Collatz Conjecture

Collatz Conjecture

就是俗稱的「 3n+1 問題」,至今尚未有人能證明其正確性。有趣的是,目前也尚未檢查出任何反例。

Iterative Method ,用迴圈實作。

只要一步一步地計算,最後便能解出答案來。

 int step(int n) // 計算出 n 收斂到 1 所經過的次數{    int t;      // 次數    for (t = 0; n > 1; ++t) // 一步一步趨近答案        if (n % 2 == 0)            n /= 2;        else            n = n * 3 + 1;                return t;}

Iterative Method ,將迴圈改為遞迴。

仍舊是一步一步地計算,但改為遞迴呼叫下一步,可說是吃飽太閒。

 int t = 0;  // 次數 void PRocess(int n) // 處理一個步驟(當數值為 n 時){    if (n == 1) return; // 已經到了最後一個步驟了     ///////////////////////////////////////        if (n % 2 == 0) // 開始進行目前的步驟        n /= 2;    else        n = n * 3 + 1;     t++;            // 累計步驟數目     process(n);     // 繼續下一個步驟}

Recursive Method

將問題反覆拆解成更小的問題。在 Collatz Conjecture 中,數字會逐步收斂──這也就是說,數字經過除以二、乘以三再加一的計算後,問題範疇就會縮小。在這裡,我們讓數字做了一次的計算,來縮小問題。

 int step(int n) // 計算出 n 收斂到 1 所經過的次數{    if (n == 1) return 0;   // 問題已經縮小至清晰可解,遞迴可以結束了。     ///////////////////////////////////////     if (n % 2 == 0)     // 求出經過一次計算後的 n 值        n /= 2;    else        n = n * 3 + 1;            return 1 + step(n); // 遞迴呼叫函式以反覆縮小問題                        // 答案即為 "一次計算" 加上 "小問題的答案"                        //  return step(n) + 1; 也可以}

討論

如果就演算法的設計策略來看,這些程式碼使用了不同的策略:前面兩支程式是 Iterative Method 、後面一支是 Recursive Method 。

但以實作的角度來看,這些程式碼卻又重新分為兩種樣式:前面一支程式是迴圈、後面兩支是長得差不多的遞迴。

以後面兩支程式來看,或許有人會覺得第二支的遞迴程式碼寫的不漂亮,只要改寫一下就是第三支的簡潔程式了。然而第二支程式和第三支程式,他們的設計理念是截然不同的。

由此可知,只是粗淺地閱讀程式碼,不見得就能夠了解整個解題思路的。設計方法(解題方法)和實作方式,這兩件事得好好的分辨清楚呀!

閒聊

這些程式都還可以再改進,讓執行效率變得更好。各位自行發揮創意吧!

另外,這個問題亦可歸類於是簡單的 Simulation 問題。

以下是我找到的相關類題:

UVa 100 371 694

Stairs Climbing

爬樓梯

這裡介紹一個知名的爬樓梯問題:眼前有五階樓梯,每次可踏上一階或踏上兩階,那麼爬完五階共有幾種踏法?例如 (1,1,1,1,1) 是其中一種踏法, (1,2,1,1) 是另一種不同的踏法。

Iterative Method

我們先試著只爬少少的幾階樓梯,觀察一下踏法。

爬完一階的踏法很明顯的只有一種: (1) 。

至於爬完兩階的踏法有兩種: (1,1) 和 (2) 。

至於爬完三階的踏法:因為一次只能往上踏一階或兩階,所以只可能從第一階或從第二階踏上第三階。只要將 ( 爬完一階的踏法 ,1) ,再綜合 ( 爬完兩階的踏法,2) ,就是爬完三階的踏法。至於踏法種類數可直接相加求得。

同理,只要將 ( 爬完兩階的踏法 ,1) ,再綜合 ( 爬完三階的踏法 ,2) ,就是爬完四階的踏法。至於踏法種類數可直接相加求得。

迭代下去,就可求出爬完五階的踏法種類。

 int stairs_climbing(int n = 5){    if (n == 1) return 1;    else if (n == 2) return 2;     int a = 1;  // 爬完一階的踏法種類    int b = 2;  // 爬完兩階的踏法種類    int c;     // 依次求爬完三階到爬完n階的踏法種類    for (int i=3; i<=n; ++i)    {        c = a + b;        a = b;        b = c;    }    return c;}

Recursive Method

我們由踏出的最後一步開始分析。

要「爬完五階」,最後一步一定是踏上第五階。要踏上第五階,只可能從第四階和第三階踏過來,也就是( 爬完四階的踏法 ,1) ,再綜合 ( 爬完三階的踏法 ,2) 。至於踏法種類數可直接相加求得。

但是我們不知道如何「爬完四階」和「爬完三階」,所以只好再分別研究「爬完四階」與「爬完三階」,反正它們一定又是由更之前的樓梯踏過來。只要不斷追究下去,問題必會漸漸簡單明朗,總有一天會撥雲見日。

追究到「爬完一階」與「爬完兩階」的時候,已經可以確認答案了。現在「爬完五階」的踏法種類也就清楚了!

 int stairs_climbing(int n = 5){    if (n == 1) return 1;    else if (n == 2) return 2;     return stairs_climb(n-1) + stars_climb(n-2);}
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表