--- tags: Algorithm --- # JavaScript 初探 A&D - 遞迴 在數學上有一個數列,稱為費氏數列(Fibonacci) 或稱 斐波那契數列,這個數列由 0 和 1 開始,之後的數是由之前的兩數相加而得出。 ```jsx 0 1 1 2 3 5 8 13 21 34 55 89 144 ... ``` 以數學上的定義來說: - $f_0 = 0$ ; $f_1=1$ ; - $f_n\;=\;f_{n-1}\;+\;f_{n-2}$  來源:[Hanna](https://ithelp.ithome.com.tw/articles/10221370) 可以發現,透過推導後得出的第二項公式,就能夠將無窮級數帶入並得出結論,因此可以說成是,**將一個複雜的問題,拆分成具有相同性質的子問題**,簡單來說,就是自己定義自己,如果將上述的概念帶入程式中,就是遞迴了。 ## 基本規則 遞迴有兩個條件: - 終止條件 ⇒ 也稱作基本條件,什麼時候結束,最尾端的要怎麼做,不然就會無限輪迴 - 遞迴條件 ⇒ 呼叫自己的條件 ## 範例 - 總和 講到遞迴,最淺白的反例就是正整數 n 的總和,我們先來看看如果是採用迴圈是如何做的: ```jsx function sum(num){ let res = 0 for(let i=0 ; i<= num ; i++){ res += i } return res } sum(100) // =>5050 ``` 接下來,讓我們以遞迴的方式思考,基本上可以把這個函式看成: $S(n)=n+n−1+…+1$ - 基本條件:$S(1)=1$ - 遞迴條件:對於每個大於 1 的整數 $S(n) = n + S(n - 1)S(n)=n+S(n−1)$ 最後就會變成: ```jsx function sum(num){ if(n === 1) return 1 return n + sum(n-1) } sum(100) // =>5050 ``` 如果按照一步一步分解,可以看成是: ``` sum(100) 100 + sum(99) 99 + sum(98) 97 + sum(96) ... 2 + sum(1) return 1 // 1 return 2 + 1 // 3 return 3 + 3 // 6 return 4 + 6 // 10 return 5 + 10 // 15 ... ``` ## 範例 - 階乘 我們也可以使用遞迴創造出階乘(factorial): - 基本條件:$0! = 1$ - 遞迴條件:$n!=1×2×3…(n−2)×(n−1)×n$ ⇒ $n!=n×(n−1)!$ ```jsx function factorial(n){ if( n === 0) return 1 return n* factorial(n-1) } ``` ## 範例 - 費氏數列 - 基本條件:$f_0 = 0$ ; $f_1=1$ ; - 遞迴條件:$f_n\;=\;f_{n-1}\;+\;f_{n-2}$ ```jsx function fibonacci(n){ if(n < 2) return n return fibonacci(n-1)+fibonacci(n-2) } ``` ## 遞迴 vs 迭代 ### 迭代: - 迴圈結構,是由下而上(Bottom-Up),一步步逼近答案; - 用新值覆蓋舊值,直到滿足條件後結束,因為不保存中間值,因此不會消耗很多記憶體空間。 ### 遞迴: - 選擇結構,是由上而下(Top-Down),慢慢地將問題縮小,來求得答案; - 將問題分解成干個子問題,再回頭運算答案,因此會消耗大量記憶體空間,但程式碼簡單明瞭。 ## 遞迴的優缺點 ### 優點: - 大問題化為小問題,程式碼簡潔清晰,可讀性佳。 ### 缺點: - 容易產生 [堆疊溢位(stack overflow)](https://zh.wikipedia.org/wiki/%E5%A0%86%E7%96%8A%E6%BA%A2%E4%BD%8D),因此非必要,不建議使用遞迴; - 冗餘計算,若子問題彼此非獨立的,會重複計算。 也就是說,雖然遞迴看起來比較簡潔專業,但並沒有比較快且消耗大量記憶體。 # 總結 雖然遞迴看起來簡潔有力,相比於迭代更符合 Functional Program ,但根本上的問題卻是效能差異,因此如果想使用遞迴,更好的辦法就是了解[尾遞迴](https://zhuanlan.zhihu.com/p/36587160),或是 [Algorithm - ****動態規劃 Dynamic programming****](https://www.notion.so/Algorithm-Dynamic-programming-7ebf4e690e7e4174a7dc07d873ff933f) ,藉由 Memorize 和 cache 去優化遞回的效能。 # 參考連結 [https://chupai.github.io/posts/2008/alg_recursion/](https://chupai.github.io/posts/2008/alg_recursion/)
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up