循环中的递归函数
Recursive function inside of a loop
我一直在研究递归函数,我开始或多或少地理解它们。当我遇到这个问题时,我正在进行一个免费的代码阵营挑战,我不理解它。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, [2],[3, [[4]]]]
- 循环从第一个索引开始:
1
,它不是一个数组,因此它被推送到结果数组 - 下一个循环迭代的索引是
[2]
,它是一个数组,因此是递归的 - 对函数的第一个递归调用接收
[2]
并对其进行迭代 - 这个递归调用的第一次迭代发现索引是
2
,它不是数组,因此被推送到结果数组 - 。。。继续
我们看到的是,当使用递归函数迭代嵌套数组时,无论嵌套程度如何,我们最终总是获得内部整数值。
听起来你的心理混乱主要与"堆栈"的工作方式有关。
基本函数调用在被调用时暂停执行,并遍历函数内部的每一行,然后在函数外部继续执行。而且,您可以在其他函数中运行函数;那么多你可能已经知道了。
这里需要理解的重要内容是程序正在跟踪的所有内容。对于初学者来说,程序会跟踪被调用的位置,这样它就可以在堆栈中"弹出一个"并继续。例如,在执行的中点,堆栈可能是这样的(知道它在哪个函数/行):
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]
- 递归函数中断
- 将jQuery对象传递到setTimeout递归函数中
- Javascript-用于展开数组的递归/for循环
- 对象与递归函数的比较
- 循环内部的递归函数未按预期工作
- 递归函数返回不正确
- 递归函数编程困境
- 我怎样才能把它变成一个循环,而不是一个递归函数
- 将 for 循环转换为递归函数
- JavaScript 中的递归函数或循环
- 循环中的递归函数
- 递归函数在多次循环javascript时崩溃
- Javascript中产生无限循环的递归函数
- 递归函数中的For循环
- 如何在递归函数中跳出循环
- 为什么递归函数中的循环在javascript中不完整
- 编写一个递归函数,迭代嵌套循环的深度未知
- 对于递归函数中的循环未完成
- 递归函数在嵌套循环中没有被调用
- 如何在递归函数中突破for循环并在Javascript中返回