给定一个每个节点具有可变数量的子节点的有向树 T,我想找到一条从根开始的“好”节点的 PATH_SIZE 大小的路径。
每个节点都有一个isGood()
方法和一个getChildren()
按预期工作的方法。
一个简单的 DFS 递归解决方案如下所示:(如果我错了,请纠正我)
function findGoodPath(node, depth){
if(!node.isGood()){
return null;
} else if (depth==PATH_SIZE){
return [node];
}
var children = node.getChildren();
for (var i=0; i<children.length; i++){
var result = findGoodPath(children[i], depth+1);
if (result){
return result.concat([node]);
}
}
return null;
}
findGoodPath(root, 1)
如果存在,调用应该找到结果。
现在问题来了:getChildren()
节点对象的方法实际上是一个在幕后进行 I/O 的异步方法。它什么也不返回,并期望一个回调参数来处理返回的孩子。
修改后的代码解决方案(错误)可能如下所示:
function findGoodPath(node, depth){
if(!node.isGood()){
return null;
} else if (depth==PATH_SIZE){
return [node];
}
node.getChildren(function(children){
for (var i=0; i<children.length; i++){
var result = findGoodPath(children[i], depth+1);
if (result){
return result.concat([node]);
}
}
});
}
这个解决方案行不通:单个节点的子节点的所有 getChildren 方法将被立即调用,因此它实际上会执行 BFS。更糟糕的是,return 语句与匿名回调函数相关联,并将在封闭函数完成运行后执行。
很明显,需要某种流量控制机制。这个问题的简单而优雅的解决方案是什么?
更新:我接受了 Sebastien 的回答,因为它通过递归解决了这个问题,这就是我提出问题的方式。我还发布了一个使用异步库while循环的答案,这就是我最终使用的。Sebastien 非常友好地在这里对这两种方法进行了基准测试。 (剧透:性能相同)