我有以下递归函数:
function explore(v, componentN) {
return function () {
nodes[v].visited = true;
nodes[v].componentNumber = componentN;
preVisit(v);
adjList[v].forEach((item) => {
if (!nodes[item].visited){
ex(item, componentN)
}
});
postVisit(v);
return nodes;
}
}
function ex(item, com){
trampoline(function () {
return explore(item, com)
})
}
function trampoline(fn) {
while(fn && typeof fn === 'function') {
fn = fn()
}
}
我想使用setImmediate()
以避免堆栈溢出问题(它应该以这种方式实现,而不是在迭代方法中实现)。但是,当我执行这个函数时,我只使用第一个元素得到数组res
,而如果我不使用setImmediate()
,我会得到所有元素,并且当我使用{时出现相同的情况{1}}(我事先知道应该有多少元素)。我做错了什么,如何在这里正确实现这个功能(或模拟)?
这是应用蹦床前的nextTick()
功能
explore()
它接受两个参数:function explore(v, componentN) {
nodes[v].visited = true;
nodes[v].componentNumber = componentN;
preVisit(v);
adjList[v].forEach((item) => {
if (!nodes[item].visited){
explore(item, componentN)
}
});
postVisit(v);
return nodes;
}
是v
数组中的索引,该元素应该被探索,而nodes
只是图形中组件的计数器。 componentN
不返回任何内容,它只是将explore()
键下的数组nodes
中的对象状态从未探测到探索更改。主要问题是两个函数v
和preVisit(v)
也改变了该对象的状态 - 第一次访问它的写入顺序和第二次(从先前的调用中弹出堆栈时) ) 分别。当我用蹦床转换postVisit(v)
时,他们开始写出意想不到的错误结果。
以这种方式在另一个函数中调用该函数:
explore()
两个函数for (let i = 0; i < vNum; i++) {
if (nodes[i].visited) continue;
explore(i, cN);
cN++;
}
和postVisit
preVisit
答案 0 :(得分:0)
假设我们有一个像这样的普通递归函数 - 这里的问题是我们有一个forEach
循环,每次调用explore
都可以产生0,1或更多对{{1}的额外调用 - 为了解决这个问题,我们需要一些方法对所有节点进行排序,这样我们就可以逐个处理它们而不会炸毁堆栈
explore
我们在const explore = node =>
{
node.visited = true
preVisit (node)
Array.from (node.adjacencies)
.filter (n => n.visited === false)
.forEach (n => explore (n))
postVisit (node)
}
函数内部引入了一个主循环,它处理节点的数组,而不仅仅是单个节点。当数组中有节点时,循环将继续运行。将对内部循环函数而不是外部explore
函数进行递归调用。这种数组方法效果很好,因为每个节点都有一定数量的邻接 - 当可以轻松地将0,1或更多相邻节点添加到此列表时 - 还要注意添加了延续explore
,这样我们就可以对postVisit以正确的顺序调用
最重要的是,对k
的递归调用是在尾部位置 - 这使我们为下一次转换做好准备
loop
一旦我们有一个尾递归循环,我们就可以为堆栈安全递归引入const explore = node =>
{
const loop = ([x, ...xs], k) =>
{
if (x === undefined)
k ()
else {
x.visited = true
preVisit (x)
loop (
Array.from (x.adjacencies)
.filter (n => n.visited === false)
.concat (xs),
() => (postVisit (x), k ())
)
}
}
return loop ([node], x => x)
}
/ loop
recur