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

更新於 發佈於 閱讀時間約 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
0會員
28內容數
留言
avatar-img
留言分享你的想法!
koko的沙龍 的其他內容
調用棧是 JavaScript 引擎用來管理函數執行的一種資料結構。 它就像一個垂直的待辦清單,追踪當前正在執行的函數,以及它們的順序。 核心特點 遵循「後進先出」(LIFO, Last In First Out)的規則。 每個函數調用會被「推入」
閉包是指一個函數能夠「記住」它被創建時的外部環境(作用域),即使那個外部環境已經不存在了。 簡單來說,閉包就像是函數帶著一個「記憶背包」,裡面裝著它出生時能看到的變數。
作用域是指程式中變數的可訪問範圍,也就是變數在哪裡可以被存取。 JavaScript 有幾種作用域類型: 1.全域作用域(Global Scope) 變數在程式最外層定義,任何地方都可以存取。 var globalVar1 = "我是全域的1"; let globalV
什麼是提升?在 JavaScript 中,提升是指變數和函數宣告會在程式執行前被「提升」到它們所在作用域(scope)的頂部。這是 JavaScript 引擎處理程式碼時的一種行為,讓你在宣告之前就能使用某些變數或函數。
什麼是執行環境(Execution Context)? 簡單來說,執行環境是 JavaScript 程式碼執行時所在的「環境」。 它決定了程式碼如何被解析和執行,並管理變數、函數以及作用域(scope)的存取。 每當程式碼執行時,JavaScript 引擎會建立一個執行環境。
for...of 需要迭代的是具有迭代器的可迭代物件。一般的物件,除非你為它定義迭代器,否則不能使用 for...of。它主要用來迭代「值」。 for...in 迭代的是物件的可枚舉屬性,在陣列中就會迭代索引。通常用來迭代物件屬性,在陣列中較不適合,也較容易出錯。
調用棧是 JavaScript 引擎用來管理函數執行的一種資料結構。 它就像一個垂直的待辦清單,追踪當前正在執行的函數,以及它們的順序。 核心特點 遵循「後進先出」(LIFO, Last In First Out)的規則。 每個函數調用會被「推入」
閉包是指一個函數能夠「記住」它被創建時的外部環境(作用域),即使那個外部環境已經不存在了。 簡單來說,閉包就像是函數帶著一個「記憶背包」,裡面裝著它出生時能看到的變數。
作用域是指程式中變數的可訪問範圍,也就是變數在哪裡可以被存取。 JavaScript 有幾種作用域類型: 1.全域作用域(Global Scope) 變數在程式最外層定義,任何地方都可以存取。 var globalVar1 = "我是全域的1"; let globalV
什麼是提升?在 JavaScript 中,提升是指變數和函數宣告會在程式執行前被「提升」到它們所在作用域(scope)的頂部。這是 JavaScript 引擎處理程式碼時的一種行為,讓你在宣告之前就能使用某些變數或函數。
什麼是執行環境(Execution Context)? 簡單來說,執行環境是 JavaScript 程式碼執行時所在的「環境」。 它決定了程式碼如何被解析和執行,並管理變數、函數以及作用域(scope)的存取。 每當程式碼執行時,JavaScript 引擎會建立一個執行環境。
for...of 需要迭代的是具有迭代器的可迭代物件。一般的物件,除非你為它定義迭代器,否則不能使用 for...of。它主要用來迭代「值」。 for...in 迭代的是物件的可枚舉屬性,在陣列中就會迭代索引。通常用來迭代物件屬性,在陣列中較不適合,也較容易出錯。
你可能也想看
Google News 追蹤
Thumbnail
全方位分析脫離繼承戰的方法,大膽猜測誰會成為卡丁國下一任國王。
Thumbnail
for loop、while loop、repeat
Thumbnail
本文章討論如何使用動態規劃和回頭查看技巧來計算最長遞增子序列的長度,並提供了相關的測試案例和範例。本文還包括了詳細的演算法和程式碼示例,以及時間和空間複雜度的分析。
Thumbnail
這篇文章,會帶大家快速回顧DFS+回溯法框架(還沒看過或想複習的可以點連結進去)。 用DFS+回溯法框架,解開 直線排列Permutations 的全系列題目。 幫助讀者鞏固DFS+回溯法框架這個重要的知識點。 回顧 DFS+回溯法框架 白話的意思 # 列舉所有可能的情況,遞迴展開所有分
Thumbnail
這篇文章,會帶著大家複習以前學過的數列DP框架, 並且以費式數列、爬樓梯、骨牌拚接的應用與遞迴數列概念為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 數列DP與遞迴數列常見的形式 如果是遞迴數列,常常看到以函數型式表達
※ 迴圈控制的兩個指令:break(跳脫)、continue(繼續) break(跳脫):當遇到一個需要強制脫離迴圈的情境,使用break(跳脫)就會直接跳出迴圈。 continue(繼續):用於跳過迴圈目前的迭代,直接開始下一次迭代的執行。 造成無限迴圈的例子: 說明: 當 x 的值
※ 何謂巢狀迴圈(NESTD LOOP): 指的是一個迴圈內包含另一個迴圈的結構。在程式設計中,這種結構常用於需要進行多層次迭代的場合,例如處理多維數組、逐行逐列處理表格資料等。 ※ 例子:九九乘法表 說明: 外層迴圈:for (let i = 1; i <= 9; i = i + 1) 這
※ 迴圈(for loop)介紹: 迴圈的用途是重複執行程式碼,只要條件滿足,就會執行特定的動作。 for (let i = 0; i < 10; i = i + 1) { console.log(i); } 說明: for:對於。 let:因為迭代器的數值會一直改變所以要用let
Thumbnail
分享在網路上看到的陣列題目。通常 for...of 的 value 是陣列中的每個值,那如果我們在迭代中對陣列操作會發生什麼事? 題目來源:https://x.com/_jayphelps/status/1774640511158022335?s=20
Thumbnail
這篇文章,會帶著大家複習以前學過的遞回框架, 並且鏈結串列的概念與應用為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 遞回框架 尋找共通模式(common pattern),對應到演算法的General case 確立初始條件(initial conditio
Thumbnail
巢狀迴圈For loop介紹結構及範例說明 巢狀迴圈 巢狀迴圈是在一個迴圈內包含另一個迴圈的結構 簡單來說,就是內迴圈做完,才會在跑到外迴圈,接著在做內迴圈
Thumbnail
全方位分析脫離繼承戰的方法,大膽猜測誰會成為卡丁國下一任國王。
Thumbnail
for loop、while loop、repeat
Thumbnail
本文章討論如何使用動態規劃和回頭查看技巧來計算最長遞增子序列的長度,並提供了相關的測試案例和範例。本文還包括了詳細的演算法和程式碼示例,以及時間和空間複雜度的分析。
Thumbnail
這篇文章,會帶大家快速回顧DFS+回溯法框架(還沒看過或想複習的可以點連結進去)。 用DFS+回溯法框架,解開 直線排列Permutations 的全系列題目。 幫助讀者鞏固DFS+回溯法框架這個重要的知識點。 回顧 DFS+回溯法框架 白話的意思 # 列舉所有可能的情況,遞迴展開所有分
Thumbnail
這篇文章,會帶著大家複習以前學過的數列DP框架, 並且以費式數列、爬樓梯、骨牌拚接的應用與遞迴數列概念為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 數列DP與遞迴數列常見的形式 如果是遞迴數列,常常看到以函數型式表達
※ 迴圈控制的兩個指令:break(跳脫)、continue(繼續) break(跳脫):當遇到一個需要強制脫離迴圈的情境,使用break(跳脫)就會直接跳出迴圈。 continue(繼續):用於跳過迴圈目前的迭代,直接開始下一次迭代的執行。 造成無限迴圈的例子: 說明: 當 x 的值
※ 何謂巢狀迴圈(NESTD LOOP): 指的是一個迴圈內包含另一個迴圈的結構。在程式設計中,這種結構常用於需要進行多層次迭代的場合,例如處理多維數組、逐行逐列處理表格資料等。 ※ 例子:九九乘法表 說明: 外層迴圈:for (let i = 1; i <= 9; i = i + 1) 這
※ 迴圈(for loop)介紹: 迴圈的用途是重複執行程式碼,只要條件滿足,就會執行特定的動作。 for (let i = 0; i < 10; i = i + 1) { console.log(i); } 說明: for:對於。 let:因為迭代器的數值會一直改變所以要用let
Thumbnail
分享在網路上看到的陣列題目。通常 for...of 的 value 是陣列中的每個值,那如果我們在迭代中對陣列操作會發生什麼事? 題目來源:https://x.com/_jayphelps/status/1774640511158022335?s=20
Thumbnail
這篇文章,會帶著大家複習以前學過的遞回框架, 並且鏈結串列的概念與應用為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 遞回框架 尋找共通模式(common pattern),對應到演算法的General case 確立初始條件(initial conditio
Thumbnail
巢狀迴圈For loop介紹結構及範例說明 巢狀迴圈 巢狀迴圈是在一個迴圈內包含另一個迴圈的結構 簡單來說,就是內迴圈做完,才會在跑到外迴圈,接著在做內迴圈