递归:在变量中存储多个值

时间:2020-05-04 19:39:04

标签: javascript recursion

代码显示了一个递归函数,该函数采用一个数字,即n = 5,并返回从n倒数到1的数组,即[5,4,3,2,1]。

我的困惑就在我们将n的数字/值推送到 countArray 之前。我的理解是 countup(n-1)将生成数字(例如n = 5)5,4,3,2,1 ...但是我不知道它们在哪里/如何存储。我以为n会以其最后定义的值n = 1或空白数组结束。但这是不正确的,并且我将它们全部以某种方式推送到一个数组中,据我所知,该数组在推送到数组之前从未创建/定义。因此,这两行带有注释是我需要帮助理解的两行。

tl; dr: (1)在存储到数组中之前如何存储值5-> 1而不覆盖最终值1? (2)在我们将 countArray 定义为数组之前/在何处/如何将其定义为数组;

function countup(n) {
  if (n < 1) {
    return [];
  } else {
    const countArray = countup(n - 1);  //the storing of 5,4,3,2,1 I don't understand
    countArray.push(n); //I don't understand when countArray was defined as an array
    return countArray;
  }
}
console.log(countup(5)); // [ 1, 2, 3, 4, 5 ]

编辑:该帖子的标题可能需要更改为数组,而不是变量等。

5 个答案:

答案 0 :(得分:3)

也许添加一些日志记录可能会使其更加清晰。

我们可以添加一个简单的记录器,报告如下所示的值:

//... Do something part

因此数组是在基本情况下定义的。然后,当我们以自己的方式备份调用堆栈时,便将其添加到其中。可以使用其他方法来完成此操作,但这是解决该问题的一种常见且合理的方法。

您可以在以下代码段中看到我如何添加日志记录:

Calling with 5
|   Calling with 4
|   |   Calling with 3
|   |   |   Calling with 2
|   |   |   |   Calling with 1
|   |   |   |   |   Calling with 0
|   |   |   |   |   Returning [] (base case)
|   |   |   |   Pushing 1 to []
|   |   |   |   Returning [1]
|   |   |   Pushing 2 to [1]
|   |   |   Returning [1,2]
|   |   Pushing 3 to [1,2]
|   |   Returning [1,2,3]
|   Pushing 4 to [1,2,3]
|   Returning [1,2,3,4]
Pushing 5 to [1,2,3,4]
Returning [1,2,3,4,5]
const log = (depth, message) => 
  console .log ('|   '.repeat (depth - 1)  + message)


function countup(n, depth = 1) {
  log(depth, `Calling with ${n}`)
  if (n < 1) {
    log(depth, `Returning [] (base case)`)
    return [];
  } else {
    const countArray = countup(n - 1, depth + 1);  //the storing of 5,4,3,2,1 I don't understand
    log(depth, `Pushing ${n} to [${countArray}]`)
    countArray.push(n); //I don't understand when countArray was defined as an array
    log(depth, `Returning [${countArray}]`)
    return countArray;
  }
}

countup(5)

更新

以下结果可能更清楚:

.as-console-wrapper {min-height: 100% !important; top: 0}

其中仅涉及日志记录语句的次要更改:

/ Calling with 5
|   / Calling with 4
|   |   / Calling with 3
|   |   |   / Calling with 2
|   |   |   |   / Calling with 1
|   |   |   |   |   / Calling with 0
|   |   |   |   |   \ Returning [] (base case)
|   |   |   |   | Pushing 1 to []
|   |   |   |   \ Returning [1]
|   |   |   | Pushing 2 to [1]
|   |   |   \ Returning [1,2]
|   |   | Pushing 3 to [1,2]
|   |   \ Returning [1,2,3]
|   | Pushing 4 to [1,2,3]
|   \ Returning [1,2,3,4]
| Pushing 5 to [1,2,3,4]
\ Returning [1,2,3,4,5]
const log = (depth, message) => 
  console .log ('|   '.repeat (depth - 1)  + message)
  
function countup(n, depth = 1) {
  log(depth, `/ Calling with ${n}`)
  if (n < 1) {
    log(depth, `\\ Returning [] (base case)`)
    return [];
  } else {
    const countArray = countup(n - 1, depth + 1);  //the storing of 5,4,3,2,1 I don't understand
    log(depth, `| Pushing ${n} to [${countArray}]`)
    countArray.push(n); //I don't understand when countArray was defined as an array
    log(depth, `\\ Returning [${countArray}]`)
    return countArray;
  }
}

countup(5)

答案 1 :(得分:1)

每个至少结束的递归函数都将具有停止条件。

对于您的功能

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

递归函数的另一部分是实际的递归。

这发生在这里

const countArray = countup(n - 1);

您正在调用的n少了一个。

您将点击该分支并触发递归,直到到达<1。到那时,创建数组并返回它。

然后,您将值推入该数组中。

return countArray;非常重要,这样可以将数组推送到调用函数。

您最可能缺少的是,当调用一个函数时,调用函数等待它结束,然后继续执行。

通常,如果您尝试映射堆栈并将所有调用映射到该函数,则您会理解递归函数。

答案 2 :(得分:1)

我知道这应该是注释,但是我不能在注释部分添加代码)。

我认为了解数组创建位置的最佳方法是自己遵循流程。比起可以解释的所有词语,它会让您更好地理解。

只需执行以下步骤:

  1. 在浏览器中打开控制台。按下def print_first_data(Data_list): for i in range (0,len(Data_list)): print(Data_list[i][0],end="") ,然后点击控制台标签
  2. 使用<div class="clock-box yellow dst-clock"> <div class="title">Central <span class="DSTterm">Standard</span> Time</div> <div class="sub-title">C<span class="DSTletter">S</span>T (UTC-<span class="DSTnum">6</span>)</div> <div class="time-display"> <div class="color-area"></div> <div class="clock time-text"><time zoneOffset=6>SYNCHRONIZING</time></div> </div> </div> 语句粘贴代码:

-

F12
  1. 使用debuggerfunction countup(n) { debugger; if (n < 1) { return []; } else { const countArray = countup(n - 1); //the storing of 5,4,3,2,1 I don't understand countArray.push(n); //I don't understand when countArray was defined as an array return countArray; } } console.log(countup(5)); // [ 1, 2, 3, 4, 5 ] 按钮
  2. 玩得开心!

答案 3 :(得分:0)

TL; DR

它在return [];中定义。

每次输入函数时,参数(n)都会减小,如果数组到达0,则会创建该数组。


比方说,您致电countup(2)

这将到达将调用countup(1)的其他地方。重复该过程并调用countup(0)

这不会进入else分支,而是创建并返回一个空数组。

调用方法countup(1)1添加到其中(并返回结果),而调用方countup(2)添加2

我将尝试可视化递归:

countup(2)
  2<1 --> false --> else
  countArray=countup(1)
    1<1 --> false --> else
      countArray=countup(0)
        0<1 --> true --> if
        return []
      push 1 --> [1]
      return countArray --> [1]
  push 1 -->[1,2]
  return countArray -->[1,2]

答案 4 :(得分:0)

此时

Resident

函数“等待”并引发对自身的调用,该调用仅在countup(0)处的停止条件const countArray = countup(n - 1); 处停止,该条件返回空数组并返回到对countup(1)的先前调用。此时,countArray将从countup(0)返回的值为[],并声明为一个数组,这也使以后的if (n < 1)调用有效。

变量同时存储在内存中。调用函数时,它的参数以及局部变量和返回地址都存储在内存堆栈中。

您可能想了解有关递归和调用堆栈的更多信息。

相关问题