JavaScript 中的遞迴函式是如何工作的?


本文將教你如何使用遞迴方法建立一個 JavaScript 遞迴函式——**一個呼叫自身的函式**。遞迴的過程就是函式呼叫自身。遞迴函式是指反覆呼叫自身的函式。遞迴函式中總是包含一個停止呼叫自身的條件,否則它將無限地呼叫自身。遞迴函式通常用於將一個大的問題分解成更小的子問題。遞迴函式常見於二叉樹、圖等資料結構以及二分查詢、快速排序等演算法中。

遞迴函式並不總是清晰或容易理解。如果你理解以下幾點,你將更快地閱讀和理解遞迴函式。首先,你應該始終確定函式的基本情況(base case)。向函式傳遞引數,以便它可以直接到達基本情況。確定哪些輸入至少會呼叫一次遞迴函式。

閱讀和編寫遞迴函式幾乎相同。建立一個可以透過其引數訪問的普通函式,並具有基本情況。向函式傳遞引數,以便它可以直接呼叫基本情況。傳遞啟動遞迴呼叫的後續引數。

讓我們看看不同的方法來了解遞迴在 JavaScript 中是如何工作的。

使用遞迴計算階乘

正數 n 的階乘由下式給出:

n 的階乘 (n!) = 1 * 2 * 3 * 4 *... * n

負數的階乘不存在。0 的階乘為 1。

語法

以下是遞迴函式的語法:

function recursion() {
   if(condition) {
      recursion();
   } else {
      // stop calling recursion()
   }
}
recursion();

示例

在下面的示例中,我們將演示如何在 JavaScript 中使用遞迴查詢數字的階乘。我們建立一個名為 `fact()` 的函式,帶有一個引數“b”,該引數從主函式中獲取值為 6。首先,我們檢查數字是否等於 0。如果為真,則程式將返回 1。在 else 語句中,我們將檢查 b*fact(b-1),大致相當於 6*(6-1)。在下一個遞迴中,它將是 5*(5-1),依此類推。透過這種方式,函式將繼續計算數字的階乘。函式在遞迴結束後列印輸入數字的階乘值。

<html>
<head>
   <title> Factorial using Recursion </title>
</head>
<body>
   <h2> Factorial using JavaScript recursion </h2>
   <script>
      // program to find the factorial of a number
      function fact(b) {
         // if number is 0
         if (b === 0) {
            return 1;
         }
         // if number is positive
         else {
            return b * fact(b - 1);
         }
      }
      const n = 6;
      // calling factorial() if num is non-negative
      if (n > 0) {
         let res = fact(n);
         document.write(`The factorial of ${n} is ${res}`);
      }
   </script>
</body>
</html>

在上面的輸出中,使用者可以看到遞迴後我們計算出的數字階乘為 720。

迴圈遞迴

在這種技術中,我們將觀察到函式1(a) 呼叫函式2(b),函式2(b) 呼叫函式3(c),函式3(c) 呼叫函式1(a),從而形成一個迴圈。

示例

在下面的示例中,我們建立了三個函式來理解這種方法。首先,我們建立一個名為 `funA()` 的函式,它帶有一個名為 n 的變數。我們檢查此值是否小於 0 並執行某個操作 (n-1)。此函式呼叫 `funB()`,在檢查 n 是否大於 2 後執行某個操作 (n-2)。然後 `funB()` 呼叫另一個函式 `funC()`,該函式接收引數 (n)。這就是巢狀遞迴的工作方式。

<html>
<body>
   <h2> Nested Recursion using JavaScript </h2>
   <script>
      // JavaScript program to show Cyclic Recursion
      function funA(n) {
         if (n > 0) {
            document.write(n.toFixed(0) + "</br>");
            // Fun(A) is calling fun(B)
            funB(n - 1);
         }
      }
      function funB(n) {
         if (n > 1) {
            document.write(n.toFixed(0) + "</br>");
            // Fun(B) is calling fun(C)
            funC(n - 2);
         }
      }
      function funC(n) {
         if (n > 1) {
            document.write(n.toFixed(0) + "</br>");
            // Fun(C) is calling fun(A)
            funA(n);
         }
      }
      funA(5);
   </script>
</body>
</html>

使用者可以觀察到,給 `funA()` 的第一個值為 5。然後執行 (n-1) 得到 4。然後 (n-2) 得到 2。類似地,(n) 得到 2。然後我們得到 (n-1) 為 1,傳遞給 `funB()`。

巢狀遞迴

在這種遞迴中,引數將作為遞迴呼叫由遞迴函式傳送。“遞迴中的遞迴”就是這個意思。為了理解這種遞迴,讓我們看一個例子。

語法

func(n)
{
   Return func(func(n-1))
}

引數

  • n − 用於在巢狀遞迴中執行任何計算的引數。

示例

在這個例子中,我們建立一個名為 `fun()` 的函式,它從驅動程式中獲取值為 **num**。這裡我們建立了一個名為 `nested` 的函式,它接受一個整數引數。在這個函式內部有一個 if-else 塊,它檢查 **num**> 100,如果是則返回 **num** - 10,否則返回 `nested(nested(num + 11))`。

<html>
<body>
   <h3> JavaScript program to show Nested Recursion </h3>
   <script>
      function fun(num){ 
         // A recursive function passing parameter
         // as a recursive call or recursion
         // inside the recursion
         if (num > 100)
            return (num - 10);
         else
            return fun(fun(num + 11));
      }
      var r;
      r = fun(98);
      document.write(r);
   </script>
</body>
</html>

輸出顯示作為 `num` 傳遞的 98 將如何被遞迴呼叫,最終得到 91 的值。

結論

這三種方法闡明瞭執行遞迴的不同方法。第一種方法是一種簡單的方法,幫助使用者計算數字的階乘。第二種方法有助於瞭解如何使用迴圈遞迴技術使用三個函式執行遞迴。第三種方法展示了巢狀遞迴如何在 JavaScript 中發生。

更新於:2022年7月22日

568 次瀏覽

啟動您的 職業生涯

完成課程獲得認證

開始學習
廣告