循环中的递归函数

Recursive function inside of a loop

本文关键字:递归函数 循环      更新时间:2023-09-26

我一直在研究递归函数,我开始或多或少地理解它们。当我遇到这个问题时,我正在进行一个免费的代码阵营挑战,我不理解它。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方法内部被再次调用,对吗?但循环会发生什么呢?concat方法内部的函数调用是否强制循环退出?

这是一个JSFiddle,我把每个newArr都记录到控制台上,但我甚至无法跟踪它

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

谢谢。

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

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

concat的调用仅在循环的当前索引上完成,这意味着结果是"0";蒸汽轧制的";当前索引的表示。

循序渐进

  1. 原始数组被传递给函数:[1, [2],[3, [[4]]]]
  2. 循环从第一个索引开始:1,它不是一个数组,因此它被推送到结果数组
  3. 下一个循环迭代的索引是[2],它是一个数组,因此是递归的
  4. 对函数的第一个递归调用接收[2]并对其进行迭代
  5. 这个递归调用的第一次迭代发现索引是2,它不是数组,因此被推送到结果数组
  6. 。。。继续

我们看到的是,当使用递归函数迭代嵌套数组时,无论嵌套程度如何,我们最终总是获得内部整数值。

听起来你的心理混乱主要与"堆栈"的工作方式有关。

基本函数调用在被调用时暂停执行,并遍历函数内部的每一行,然后在函数外部继续执行。而且,您可以在其他函数中运行函数;那么多你可能已经知道了。

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

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

然后它的当前循环达到"返回"。。。

steamroller:8
steamroller:8
main:20

但这还不是全部——它还保留了函数运行中声明的变量的每个实例。事实上,您可以拥有大约500万、600万或500万个newArr,因为这些变量是在堆栈上声明的,而不是在一个奇点中声明的。

当它进入一个函数时,这些信息——行号或实例变量——都不会被破坏——它只是保存在当前函数中的位置,并逐步通过内部函数。

有道理吗?

首先输入:

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

第一个元素不是Array,所以newArr接收"1"。第二个元素是数组,所以它再次调用蒸汽辊:

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

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

我想你已经理解了后面会发生什么,但评论你仍然需要解释3和4会发生什么。

对于递归函数,控制台的返回将是一团糟,因为与正常循环不同,它需要在返回控制台中的所有值之前完成递归树的最后一个位置,因此,如果你把数组的一个位置放在一个更深的位置,比如[[[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]

嗨,希望这能让你更好地了解递归函数

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

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]