【问题标题】:Recursion? I understand the basics but have trouble understanding the flow of this code递归?我了解基础知识,但无法理解此代码的流程
【发布时间】:2020-05-14 18:51:58
【问题描述】:

我最近迈出了学习 JavaScript 的第一步。我正在关注 FreeCodeCamp 'JavaScript Algorithms and Data Structures Certification' 轨道。

我真的很难理解递归是如何工作的,尤其是它如何与堆栈交互。我了解一些基本示例,但完全停留在这个示例上!

function countup(n) {
  if (n < 1) {
    return [];
  } else {
    const countArray = countup(n - 1);
    countArray.push(n);
    return countArray;
  }
}
console.log(countup(5)); // [ 1, 2, 3, 4, 5 ]

我知道count(n-1) 再次调用该函数,参数 1 减去 N 的原始值,但不明白它是如何实际工作的。为什么分配给const countArray?为什么最后是return countArray

谢谢!!

【问题讨论】:

  • 也许用整个代码替换对countup的每次调用会有所帮助
  • 这就是我的意思:jsfiddle.net/acdcjunior/b3n28pry/14
  • @acdcjunior:您应该将其作为答案,这是将其可视化的好方法。
  • 所以我想我终于明白是怎么回事了……我不明白在基础案例被击中后发生了什么。当 n = 0 时,我的想法是否正确,该函数返回一个空数组。然后,这允许先前的调用完成执行然后返回。然后前一个可以返回等等等等。这是正确的想法吗?感谢您的帮助!

标签: javascript recursion


【解决方案1】:

我做了一个插图,希望对你有帮助

【讨论】:

    【解决方案2】:

    const countArray = countup(n - 1); - 分配 countup 返回的值。 所以countup 应该返回一些东西。

    您可以添加控制台日志以查看发生了什么,但这里是 n=2 的演练。

    countup(2) - 2 > 1 所以它继续到 else 子句并调用 countup(1)
    countup(1) - 1 = 1 所以它继续到 else 子句并调用 countup(0)
    @ 987654329@ - 0 []。
    count(1) 在它停止的点继续 - 所以const countArray = [],在下一行它推(1)并返回[1];count(2) 在它停止的点继续 - 所以const countArray = [1],在下一行它推动 (2) 并返回 [1,2] 作为递归调用的最终结果;

    希望有帮助。

    【讨论】:

      【解决方案3】:

      我学到了一个小技巧,他们称之为“表格评估”(我不知道它是否是真实的),但它包括“手动”评估函数调用(好像你是在一张桌子上用铅笔和一张纸),用函数体替换每个函数调用并继续评估。

      好的,由于解释可能有点困难,这里是在网上做的一个尝试:

      // considering your function is this:
      function countup(n) {
        if (n < 1) {
          return [];
        } else {
          const countArray = countup(n - 1);
          countArray.push(n);
          return countArray;
        }
      }
      
      // So the call to
      console.log(countup(5));
      
      // is the same as
      console.log(if (5 < 1) {
        return [];
      } else {
        const countArray = countup(5 - 1);
        countArray.push(5);
        return countArray;
      })
      // well, actually, sort of, because the "if" block is not an expression -- I mean, this is
      // not valid code, but hopefully you'll catch the drift
      
      // below I will just repeat the function code, I won't repeat the console.log() for clarity
      
      // so the code that gets logged above is the same as (because we
      // evaluated the if in the function body and therefore picked up just the else part)
      const countArray = countup(4);
      countArray.push(5);
      return countArray;
      
      // which is [replacing the countup(4) with the function body with n=4)
      const countArray = (if (4 < 1) {
        return [];
      } else {
        const countArray = countup(4 - 1);
        countArray.push(n);
        return countArray;
      })
      countArray.push(5);
      return countArray;
      
      // which is [evaluating the if]
      const countArray = ({
        const countArray = countup(3);
        countArray.push(4);
        return countArray;
      })
      countArray.push(5);
      return countArray;
      
      // which is [countup(3)]
      const countArray = ({
        const countArray = (if (3 < 1) {
          return [];
        } else {
          const countArray = countup(3 - 1);
          countArray.push(3);
          return countArray;
        })
        countArray.push(4);
        return countArray;
      })
      countArray.push(5);
      return countArray;
      
      // which is
      const countArray = ({
        const countArray = ({
          const countArray = countup(2);
          countArray.push(3);
          return countArray;
        })
        countArray.push(4);
        return countArray;
      })
      countArray.push(5);
      return countArray;
      
      // which is
      const countArray = ({
        const countArray = ({
          const countArray = (if (2 < 1) {
            return [];
          } else {
            const countArray = countup(2 - 1);
            countArray.push(2);
            return countArray;
          })
          countArray.push(3);
          return countArray;
        })
        countArray.push(4);
        return countArray;
      })
      countArray.push(5);
      return countArray;
      
      // which is
      const countArray = ({
        const countArray = ({
          const countArray = ({
            const countArray = countup(1);
            countArray.push(2);
            return countArray;
          })
          countArray.push(3);
          return countArray;
        })
        countArray.push(4);
        return countArray;
      })
      countArray.push(5);
      return countArray;
      
      // which is
      const countArray = ({
        const countArray = ({
          const countArray = ({
            const countArray = (if (1 < 1) {
              return [];
            } else {
              const countArray = countup(1 - 1);
              countArray.push(1);
              return countArray;
            })
            countArray.push(2);
            return countArray;
          })
          countArray.push(3);
          return countArray;
        })
        countArray.push(4);
        return countArray;
      })
      countArray.push(5);
      return countArray;
      
      // which is
      const countArray = ({
        const countArray = ({
          const countArray = ({
            const countArray = ({
              const countArray = countup(0);
              countArray.push(1);
              return countArray;
            })
            countArray.push(2);
            return countArray;
          })
          countArray.push(3);
          return countArray;
        })
        countArray.push(4);
        return countArray;
      })
      countArray.push(5);
      return countArray;
      
      // which is
      const countArray = ({
        const countArray = ({
          const countArray = ({
            const countArray = ({
              const countArray = (if (0 < 1) {
                return [];
              } else {
                const countArray = countup(0 - 1);
                countArray.push(0);
                return countArray;
              })
              countArray.push(1);
              return countArray;
            })
            countArray.push(2);
            return countArray;
          })
          countArray.push(3);
          return countArray;
        })
        countArray.push(4);
        return countArray;
      })
      countArray.push(5);
      return countArray;
      
      // which is (now finally the first branch of the if...)
      const countArray = ({
        const countArray = ({
          const countArray = ({
            const countArray = ({
              const countArray = (if (true) {
                return [];
              })
              countArray.push(1);
              return countArray;
            })
            countArray.push(2);
            return countArray;
          })
          countArray.push(3);
          return countArray;
        })
        countArray.push(4);
        return countArray;
      })
      countArray.push(5);
      return countArray;
      
      // which is
      const countArray = ({
        const countArray = ({
          const countArray = ({
            const countArray = ({
              const countArray = [];
              countArray.push(1);
              return countArray;
            })
            countArray.push(2);
            return countArray;
          })
          countArray.push(3);
          return countArray;
        })
        countArray.push(4);
        return countArray;
      })
      countArray.push(5);
      return countArray;
      
      // which is
      const countArray = ({
        const countArray = ({
          const countArray = ({
            const countArray = ({
              return [1]; // was [].push(1)
            })
            countArray.push(2);
            return countArray;
          })
          countArray.push(3);
          return countArray;
        })
        countArray.push(4);
        return countArray;
      })
      countArray.push(5);
      return countArray;
      
      // which is
      const countArray = ({
        const countArray = ({
          const countArray = ({
            const countArray = [1];
            countArray.push(2);
            return countArray;
          })
          countArray.push(3);
          return countArray;
        })
        countArray.push(4);
        return countArray;
      })
      countArray.push(5);
      return countArray;
      
      // which is
      const countArray = ({
        const countArray = ({
          const countArray = ({
            return [1, 2]; // was [1].push(2)
          })
          countArray.push(3);
          return countArray;
        })
        countArray.push(4);
        return countArray;
      })
      countArray.push(5);
      return countArray;
      
      // which is
      const countArray = ({
        const countArray = ({
          const countArray = [1, 2];
          countArray.push(3);
          return countArray;
        })
        countArray.push(4);
        return countArray;
      })
      countArray.push(5);
      return countArray;
      
      // which is
      const countArray = ({
        const countArray = ({
          return [1, 2, 3]; // was [1, 2].push(3)
        })
        countArray.push(4);
        return countArray;
      })
      countArray.push(5);
      return countArray;
      
      // which is
      const countArray = ({
        const countArray = [1, 2, 3];
        countArray.push(4);
        return countArray; // was [1, 2].push(3)
      })
      countArray.push(5);
      return countArray;
      
      // which is
      const countArray = ({
        return [1, 2, 3, 4]; // was [1, 2, 3].push(4)
      })
      countArray.push(5);
      return countArray;
      
      // which is
      const countArray = [1, 2, 3, 4];
      countArray.push(5);
      return countArray;
      
      // which is
      [1, 2, 3, 4].push(5);
      return countArray;
      
      // which is (bringing the console.log back)
      console.log([1, 2, 3, 4, 5]);
      

      【讨论】:

        【解决方案4】:

        这是我回答的一些背景:

        递归是一种通过根据问题本身来定义问题来解决问题的策略。 在编程中,递归意味着函数定义将在其自身的主体中包含对该函数的调用。这是一个伪代码示例:

        考虑一下您的问题的这个伪代码: 问题:打印 1 和给定数字 n 之间的所有正数,例如如果 n3 打印1 2 3

        解决方案:

        1. 列表项
        2. 检查n是否小于1
          1. 如果是,我们的答案是0(因为它和1之间不能有任何正数)
          2. 如果不是
          3. n 中减去 1(给我们一个新的n
        3. 检查新的n看是否小于1
          1. 如果是,我们的答案是n
          2. 如果不是
          3. 从新的n 中减去 1(给我们一个新的n
        4. 检查较新的 n 以查看 ....

        正如您所看到的,该解决方案的一部分自身不断重复,这是递归的简单表示,我们在其中不断实现代码块,测试不同的情况(通过修改参数,例如从它)直到我们得到我们需要的结果。

        按照这个模式,因为我们想要获取 1 到 5 之间的所有数字,所以我们从 5 开始,检查它是否小于 1,如果不是,我们将它添加到包含 1 到 5 之间的所有值的数组中,然后我们减少5并再次检查直到我们小于1,然后我们返回数组

        我们在 Javascript 中如何处理这个问题是通过在函数体中声明函数(通过将其分配给变量),以便我们可以使用修改后的参数调用它(以测试不同的情况) 在这种情况下,countArray 是我们初始值的修改形式

        ...
            const countArray = countup(n - 1);
        ...
        

        然后我们在修改参数的函数上执行我们的逻辑,在这种情况下

        ...
            countArray.push(n);
        ...
        

        最后,我们返回最新的值(结束我们的测试),在这种情况下它是最终的数组

        ...
            return countArray;
        ...
        

        【讨论】:

          【解决方案5】:

          函数总是返回一个值,即使你没有指定,它也会返回undefinedcountup 函数在这种情况下返回一个数组,如果输入小于 1 则为空或其中包含项目。

          countArray 被分配给countup(n - 1)结果,或者换句话说,countArray 将具有被调用的countup 的值,这将是一个数组。

          然后 countArray 将一个项目添加到它的数组中,然后 countup 返回修改后的数组。

          在阅读递归代码时,首先查看基本情况,这是满足条件的部分,因此会中断以防止无限循环。基本情况是n 小于 1。它将返回空数组。

          if (n < 1) {
            return [];
          } 
          

          假设我们的输入是 3,n = 3。让我们从代码的顶部到底部开始。条件检查是否 n 小于 1 失败,所以我们跳转到 else 逻辑。

          function countup(n) {
            if (n < 1) {
              return [];
            } else {             VVVVVVV execution always pauses here until n is 0
              const countArray = countup(n - 1);
          
              /*** The rest is not run until other countups are done ***/
              countArray.push(n);
              return countArray;
            }
          

          一旦我们调用countup(n - 1),这将启动一个新的执行堆栈,其中n现在等于2,因此代码将不会继续运行其余的逻辑,因为它现在继续在新的执行堆栈上.现在代码处于创建额外堆栈的循环中,直到我们遇到n 小于 1 的情况,如下图所示。

          execution stack
          countup(0) // stops looping because we pass the base case where n < 1. 
          countup(1)
          countup(2)
          countup(3) // can't finish the logic until the other execution stacks on top of it are done
          

          现在我们终于可以继续 countArray 将当前数字推送到其数组中的逻辑

          countArray.push(n);
          return countArray;
          
          execution stack
          countup(0) // returns empty array
          countup(1)
          countup(2)
          countup(3)
          
          execution stack
          countup(1) // returns [ 1 ]
          countup(2)
          countup(3)
          
          execution stack
          countup(2) // returns [ 1, 2 ]
          countup(3)
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-08-11
            • 2021-04-07
            • 2011-06-14
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多