循环内的递归函数

时间:2015-12-04 21:04:28

标签: javascript

我一直在研究递归函数,我开始或多或少地开始理解它们。当我遇到这个并且我不理解时,我正在开展一个免费的代码阵营挑战。 for循环内部的递归函数:

function steamroller(arr) {
   var newArr = [];

    for (var i = 0; i < arr.length; i++) {
       //If (i)th element is an array
       if (Array.isArray(arr[i])) {
          newArr = newArr.concat(steamroller(arr[i]));
          console.log(newArr);
       } else {
          newArr.push(arr[i]);
       }
   }
   return newArr;
}
steamroller([1, [2],[3, [[4]]]]);
//returns [1, 2, 3, 4]

我很难理解的一句话是:

newArr = newArr.concat(steamroller(arr[i]));

在那一行,newArr被连接到什么?在.concat方法中再次调用该函数,对吧?但是那个for循环会发生什么?在concat方法内调用函数是否强制循环退出?

这是一个JSFiddle,我每个newArr都登录到控制台,但我甚至无法关注它。阵列的构建方式如下:

[1, 2]
[4]
[3, 4]
[1, 2, 3, 4] //Final

感谢。

5 个答案:

答案 0 :(得分:5)

steamroller函数需要遍历作为函数参数提供的数组中的索引,以确保看到数组的每个索引。

但是,原始数组有许多索引,而这些索引本身可能包含多个索引,所有索引都需要依次循环。

concat的调用仅在循环的当前索引上完成,这意味着结果是&#34; steamrollered&#34;当前指数的表示。

一步一步

  1. 将原始数组传递给函数:[1, [2],[3, [[4]]]]
  2. 循环从第一个索引开始:1,它不是一个数组,所以它被推送到结果数组。
  3. 下一个循环迭代的索引是[2],这是一个数组,因此被递归。
  4. 对函数的第一次递归调用接收[2]并迭代它。
  5. 此递归调用的第一次迭代查找索引为2,该索引不是数组,因此被推送到生成的数组。
  6. ...继续......
  7. 我们看到的是,当使用递归函数迭代嵌套数组时,无论嵌套如何,我们总是最终获得内部整数值。

答案 1 :(得分:1)

首先输入:

steamroller([1, [2],[3, [[4]]]])

第一个元素不是数组,因此newArr接收&#39; 1&#39;。 第二个元素是一个数组,所以它再次调用了压路器:

steamroller([1, [2],[3, [[4]]]])->steamroller(2)

它不是一个数组,因此它会将元素连接到newArr,因此它只会将2连接到一个空数组。该函数将返回它,并将[2]连接到包含[1]的newArr,现在你有[1,2],并且控制台弹出你在小提琴上看到的第一行。

我认为你得到了后者发生的事情,但是评论你还需要解释3和4会发生什么。

答案 2 :(得分:1)

这听起来像是你的精神混乱主要与#&#34; 堆栈&#34;的工作原理。

基本函数调用在被调用的位置暂停执行,并逐步执行函数内的每一行,然后在函数外部重新开始。并且,您可以在其他函数内部运行函数;你可能已经知道的很多。

这里要理解的重要一点是程序正在跟踪的所有内容。对于初学者来说,该程序会跟踪它被调用的位置,因此它可以弹出一个&#34;在堆栈中,继续。例如,在执行的中点,堆栈可能看起来像这样(知道它在哪个函数/行):

steamroller:10
steamroller:8
steamroller:8
main:20

然后它的当前循环命中&#34;返回&#34; ...

steamroller:8
steamroller:8
main:20

但并非所有 - 保留了该函数运行中声明的每个实例变量。事实上,你可以拥有大约5或6或5百万newArr s,因为这些变量是在堆栈上声明的,而不是在一个奇异点上。

这些信息 - 行号或实例变量 - 在进入函数时都不会被销毁 - 它只是在当前函数中保存它的位置,然后逐步执行内部函数。

有意义吗?

答案 3 :(得分:1)

使用递归函数是控制台的返回将是一个混乱,因为它不同于在返回控制台中的所有值之前需要完成递归树的最后位置的正常循环,所以如果你放入一个具有更深位置的数组的位置如[[[[3]]]]它将到达位置的末尾然后它将返回所有值,所以如果你放置某种控制台来看看如何正在处理你的递归函数,你将收到某种树,而不是像普通循环那样,这就是递归函数的危险,而且它们对于生产服务器中CPU使用率的内存来说可能相当沉重。因此,如果您可以通过执行任何递归函数来执行此操作,那将更好。

因此,如果您将代码更改为

 steamroller([1, [2],[3, [4]]]);
 //the return will be
 [1, 2]
 [3, 4]
 [1, 2, 3, 4]

谈论递归树中的级别 因此,如果您将[[3]]作为[[4]],则返回将与树的相同级别。

 steamroller([1, [2],[[3], [4]]]);
 //the return will be
 [1, 2]
 [3]
 [4]
 [3, 4]
 [1, 2, 3, 4]

希望能让您更好地了解递归函数

答案 4 :(得分:0)

如果我们在没有递归的情况下检查运行,那么:

i = 0 => arr[i] = 1 => newArr.push(arr[i]) => newArr = [1]
i = 1 => arr[i] = [2] => steamroller(arr[i]) = [2] => newArr = [1, 2]
i = 2 => arr[i] = [3, [[4]]] => steamroller(arr[i]) = [3, 4] => newArr = [1, 2, 3, 4]
相关问题