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
家中修繕或裝潢想要找各種小零件時,直接上網採買可以省去不少煩惱~看看Sylvia這回為了工地買了些什麼吧~
Thumbnail
家中修繕或裝潢想要找各種小零件時,直接上網採買可以省去不少煩惱~看看Sylvia這回為了工地買了些什麼吧~
Thumbnail
👜簡單生活,從整理包包開始!我的三款愛用包+隨身小物清單開箱,一起來看看我每天都帶些什麼吧🌿✨
Thumbnail
👜簡單生活,從整理包包開始!我的三款愛用包+隨身小物清單開箱,一起來看看我每天都帶些什麼吧🌿✨
Thumbnail
創作者營運專員/經理(Operations Specialist/Manager)將負責對平台成長及收入至關重要的 Partnership 夥伴創作者開發及營運。你將發揮對知識與內容變現、影響力變現的精準判斷力,找到你心中的潛力新星或有聲量的中大型創作者加入 vocus。
Thumbnail
創作者營運專員/經理(Operations Specialist/Manager)將負責對平台成長及收入至關重要的 Partnership 夥伴創作者開發及營運。你將發揮對知識與內容變現、影響力變現的精準判斷力,找到你心中的潛力新星或有聲量的中大型創作者加入 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
Thumbnail
題目已經給了依照起點升序排列好的區間陣列。 接下來新插入一個區間,插入後如果和原本的區間重疊,請把他們合併,要求我們輸出插入後的結果。 這是一個線性掃苗,所需時間為O(n)的演算法。 題目已經幫我們排序好區間順序,我們只要接著依序檢查區間、(假如有重疊的話)合併區間。
Thumbnail
題目已經給了依照起點升序排列好的區間陣列。 接下來新插入一個區間,插入後如果和原本的區間重疊,請把他們合併,要求我們輸出插入後的結果。 這是一個線性掃苗,所需時間為O(n)的演算法。 題目已經幫我們排序好區間順序,我們只要接著依序檢查區間、(假如有重疊的話)合併區間。
Thumbnail
題目敘述 題目給定我們一顆二元樹的根節點,要求我們計算出從根節點到葉子節點的偽回文路徑路徑有幾條? 偽回文路徑路徑 的定義: 路徑經過重新排列之後,可以形成回文Palindrome,也就是頭尾鏡像對稱。 ​ 例如: 1 -> 3 -> 3 重新排列之後,可以形成 3 -> 1 -> 3
Thumbnail
題目敘述 題目給定我們一顆二元樹的根節點,要求我們計算出從根節點到葉子節點的偽回文路徑路徑有幾條? 偽回文路徑路徑 的定義: 路徑經過重新排列之後,可以形成回文Palindrome,也就是頭尾鏡像對稱。 ​ 例如: 1 -> 3 -> 3 重新排列之後,可以形成 3 -> 1 -> 3
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News