JS學習筆記#23 | 遞迴(Recursion)

koko-avatar-img
發佈於JS學習
更新 發佈閱讀 5 分鐘

一、什麼是 Recursion?

遞迴是指一個函數自己呼叫自己,用來解決可以分解成相似小問題的大問題。它就像一層層深入,最後再一層層回來的過程。


二、遞迴的兩個核心要素

1.基底條件(Base Case)

告訴函數什麼時候停止,否則會無限遞迴。 通常是問題的最簡單情況。

2.遞迴步驟(Recursive Case)

函數自我調用,每次縮減問題規模,直到觸及基底條件。

3.範例:階乘

function factorial(n) {
if (n === 0) { // 基底條件
return 1;
}
return n * factorial(n - 1); // 遞迴步驟
}

console.log(factorial(5)); // 輸出:120 (5 * 4 * 3 * 2 * 1)

執行過程

  1. factorial(5) -> 5 * factorial(4)
  2. factorial(4) -> 4 * factorial(3)
  3. factorial(3) -> 3 * factorial(2)
  4. factorial(2) -> 2 * factorial(1)
  5. factorial(1) -> 1 * factorial(0)
  6. factorial(0) -> 1(基底條件)
  7. 回溯:1 * 1 * 2 * 3 * 4 * 5 = 120


視覺化

深入:5 -> 4 -> 3 -> 2 -> 1 -> 0

返回:1 -> 1 -> 2 -> 6 -> 24 -> 120


三、遞迴與調用棧(Call Stack)

遞迴依賴調用棧來記錄每層調用:

  • 每次自我調用,函數推入調用棧。
  • 達到基底條件後,棧開始彈出,計算結果。
function countDown(n) {
if (n <= 0) {
console.log("Done");
return;
}
console.log(n);
countDown(n - 1);
}

countDown(3);
// 輸出:
// 3
// 2
// 1
// Done

調用棧變化

[] -> [countDown(3)] -> [countDown(3), countDown(2)] -> [countDown(3), countDown(2), countDown(1)] -> [countDown(3), countDown(2), countDown(1), countDown(0)] -> 逐步彈出

過程:

  1. countDown(3) 推入,印 3,呼叫 countDown(2)
  2. countDown(2) 推入,印 2,呼叫 countDown(1)
  3. countDown(1) 推入,印 1,呼叫 countDown(0)
  4. countDown(0) 推入,印 "Done",返回,棧彈出。


四、遞迴的實際應用

1.數學問題:階乘、斐波那契數列。

// 斐波那契範例
function fibonacci(n) {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
console.log(fibonacci(6)); // 8 (0, 1, 1, 2, 3, 5, 8)

2.資料結構遍歷:樹或巢狀陣列

function flattenArray(arr) {
let result = [];
arr.forEach(item => {
if (Array.isArray(item)) {
result = result.concat(flattenArray(item));
} else {
result.push(item);
}
});
return result;
}
console.log(flattenArray([1, [2, 3], [4, [5]]])); // [1, 2, 3, 4, 5]

3.分治演算法:快速排序、合併排序。


五、遞迴的注意事項

1.棧溢出(Stack Overflow)

調用棧有大小限制(通常幾千層)。

如果遞迴太深或無基底條件,會溢出。

function infinite(n) {
return infinite(n + 1);
}
infinite(1); // 報錯:Maximum call stack size exceeded


2.效能問題

遞迴每次調用都推入調用棧,佔用記憶體。

對於簡單問題,迴圈可能更高效。

function factorialLoop(n) {
let result = 1;
for (let i = 1; i <= n; i++) {
result *= i;
}
return result;
}

遞迴 vs 迴圈

遞迴:程式碼簡潔,適合複雜分解問題。 佔用調用棧,效能較低。

迴圈:效能更高,記憶體使用少。 程式碼可能較冗長。

留言
avatar-img
留言分享你的想法!
avatar-img
koko的沙龍
1會員
34內容數
koko的沙龍的其他內容
2025/03/11
在 JavaScript 中,函數是物件,因此它們有內建方法可以用來控制執行方式。 這些方法包括 .call()、.apply() 和 .bind(),主要用來改變函數執行時的 this 指向或傳遞參數,特別在物件導向或繼承中很有用。
Thumbnail
2025/03/11
在 JavaScript 中,函數是物件,因此它們有內建方法可以用來控制執行方式。 這些方法包括 .call()、.apply() 和 .bind(),主要用來改變函數執行時的 this 指向或傳遞參數,特別在物件導向或繼承中很有用。
Thumbnail
2025/03/09
每個建構函數都有 prototype 屬性,是一個物件,用來存放共享的方法或屬性。 物件透過 __proto__ 連接到其原型,形成屬性和方法的查找路徑。
Thumbnail
2025/03/09
每個建構函數都有 prototype 屬性,是一個物件,用來存放共享的方法或屬性。 物件透過 __proto__ 連接到其原型,形成屬性和方法的查找路徑。
Thumbnail
2025/03/09
建構函數是 JavaScript 中用來創建和初始化物件的一種特殊函數。它像一個「模具」,透過 new 關鍵字生成多個相似的物件實例。
Thumbnail
2025/03/09
建構函數是 JavaScript 中用來創建和初始化物件的一種特殊函數。它像一個「模具」,透過 new 關鍵字生成多個相似的物件實例。
Thumbnail
看更多
你可能也想看
Thumbnail
雙11於許多人而言,不只是單純的折扣狂歡,更是行事曆裡預定的,對美好生活的憧憬。 錢錢沒有不見,它變成了快樂,跟讓臥房、辦公桌、每天早晨的咖啡香升級的樣子! 這次格編突擊辦公室,也邀請 vocus「野格團」創作者分享掀開蝦皮購物車的簾幕,「加入購物車」的瞬間,藏著哪些靈感,或是對美好生活的想像?
Thumbnail
雙11於許多人而言,不只是單純的折扣狂歡,更是行事曆裡預定的,對美好生活的憧憬。 錢錢沒有不見,它變成了快樂,跟讓臥房、辦公桌、每天早晨的咖啡香升級的樣子! 這次格編突擊辦公室,也邀請 vocus「野格團」創作者分享掀開蝦皮購物車的簾幕,「加入購物車」的瞬間,藏著哪些靈感,或是對美好生活的想像?
Thumbnail
for loop、while loop、repeat
Thumbnail
for loop、while loop、repeat
Thumbnail
本文章討論如何使用動態規劃和回頭查看技巧來計算最長遞增子序列的長度,並提供了相關的測試案例和範例。本文還包括了詳細的演算法和程式碼示例,以及時間和空間複雜度的分析。
Thumbnail
本文章討論如何使用動態規劃和回頭查看技巧來計算最長遞增子序列的長度,並提供了相關的測試案例和範例。本文還包括了詳細的演算法和程式碼示例,以及時間和空間複雜度的分析。
Thumbnail
這篇文章,會帶大家快速回顧DFS+回溯法框架(還沒看過或想複習的可以點連結進去)。 用DFS+回溯法框架,解開 直線排列Permutations 的全系列題目。 幫助讀者鞏固DFS+回溯法框架這個重要的知識點。 回顧 DFS+回溯法框架 白話的意思 # 列舉所有可能的情況,遞迴展開所有分
Thumbnail
這篇文章,會帶大家快速回顧DFS+回溯法框架(還沒看過或想複習的可以點連結進去)。 用DFS+回溯法框架,解開 直線排列Permutations 的全系列題目。 幫助讀者鞏固DFS+回溯法框架這個重要的知識點。 回顧 DFS+回溯法框架 白話的意思 # 列舉所有可能的情況,遞迴展開所有分
Thumbnail
這篇文章,會帶大家快速回顧DFS+回溯法框架(還沒看過或想複習的可以點連結進去)。 用DFS+回溯法框架,解開 組合數之和 Combination Sum 的全系列題目。 幫助讀者鞏固DFS+回溯法框架這個重要的知識點。 回顧 DFS+回溯法框架 白話的意思 # 列舉所以可能的情況,
Thumbnail
這篇文章,會帶大家快速回顧DFS+回溯法框架(還沒看過或想複習的可以點連結進去)。 用DFS+回溯法框架,解開 組合數之和 Combination Sum 的全系列題目。 幫助讀者鞏固DFS+回溯法框架這個重要的知識點。 回顧 DFS+回溯法框架 白話的意思 # 列舉所以可能的情況,
Thumbnail
這篇文章,會帶著大家複習以前學過的數列DP框架, 並且以費式數列、爬樓梯、骨牌拚接的應用與遞迴數列概念為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 數列DP與遞迴數列常見的形式 如果是遞迴數列,常常看到以函數型式表達
Thumbnail
這篇文章,會帶著大家複習以前學過的數列DP框架, 並且以費式數列、爬樓梯、骨牌拚接的應用與遞迴數列概念為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 數列DP與遞迴數列常見的形式 如果是遞迴數列,常常看到以函數型式表達
Thumbnail
分享在網路上看到的陣列題目。通常 for...of 的 value 是陣列中的每個值,那如果我們在迭代中對陣列操作會發生什麼事? 題目來源:https://x.com/_jayphelps/status/1774640511158022335?s=20
Thumbnail
分享在網路上看到的陣列題目。通常 for...of 的 value 是陣列中的每個值,那如果我們在迭代中對陣列操作會發生什麼事? 題目來源:https://x.com/_jayphelps/status/1774640511158022335?s=20
Thumbnail
這篇文章,會帶著大家複習以前學過的遞回框架, 並且鏈結串列的概念與應用為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 遞回框架 尋找共通模式(common pattern),對應到演算法的General case 確立初始條件(initial conditio
Thumbnail
這篇文章,會帶著大家複習以前學過的遞回框架, 並且鏈結串列的概念與應用為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 遞回框架 尋找共通模式(common pattern),對應到演算法的General case 確立初始條件(initial conditio
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News