在javascript中说我有一棵树,如下所示:
let rootNode = {name:'', children:[
{name:'0', children:[
{name:'00', children:[]},
{name:'01', children:[
{name:'010', children:[]},
]},
{name:'02', children:[]},
]},
{name:'1', children:[
{name:'10', children:[]},
]},
]};
我想对它进行前序遍历,我可以这样做:
function preOrderTraversalRecursive(rootNode, visitNodeCallback) {
function recurse(node) {
visitNodeCallback(node);
for (let childNode of node.children)
recurse(childNode);
}
recurse(rootNode);
};
console.log("Pre-order traveral, recursive:");
preOrderTraversalRecursive(rootNode, function visitNodeCallback(node) {
console.log(" '"+node.name+"'");
});
给出了预期的输出:
Pre-order traveral, recursive:
''
'0'
'00'
'01'
'010'
'02'
'1'
'10'
现在让我们说我想做同样的事情ES6发电机式。我以为这会是这样的:
function *preOrderGeneratorIteratorRecursive(rootNode) {
function recurse(node) {
yield node;
for (let childNode of node.children)
recurse(childNode);
}
recurse(rootNode);
};
console.log("Pre-order generator iterator, recursive:");
for (let node of preOrderGeneratorIteratorRecursive(rootNode)) {
console.log(" '"+node.name+"'");
}
但显然这是非法的:Uncaught SyntaxError: Unexpected strict mode reserved word
yield
。
令人失望!我缺少一些语法吗? 制作表达此算法的生成器的最简洁方法是什么? 也许使用一些帮助库?
我知道我可以使用如下的显式堆栈,但由于以下几个原因,这并不令人满意: (1)逻辑被模糊到没有的地步 使用发电机的可读性优势;不妨回去吧 到递归回调版本,和 (2)它不是真正相同的算法,因为它是向后迭代的 在每个node.children上。特别是,这意味着它不起作用 如果node.children是其他类型的可迭代的,可能来自另一个生成器。
function *preOrderTraversalIteratorGeneratorExplicitStackCheating(rootNode) {
let stack = [rootNode];
while (stack.length > 0) {
let node = stack.pop();
yield node;
for (let i = node.children.length-1; i >= 0; --i) // backwards
stack.push(node.children[i]);
}
} // preOrderIteratorGeneratorExplicitStackCheating
console.log("Pre-order traveral of tree with explicit stack, cheating:");
for (let node of preOrderTraversalIteratorGeneratorExplicitStackCheating(rootNode)) {
console.log(" '"+node.name+"'");
}
要明确:我对隐藏可怕细节的特殊帮助者不感兴趣 显式堆栈遍历实现。 我想知道是否有一种方法可以清楚地编写迭代器生成器算法,即使它们恰好是递归的。
答案 0 :(得分:2)
确实为yield*
运算符提供了此功能。从本质上讲,您需要将此视为一个将其功能委托给另一个的生成器。 (实际上,您可以委托任何可迭代的值。)
例如,你可以这样做:
function *pointlessGenerator() {
yield* [1, 2, 3, 4];
}
这将产生1
,2
,3
和4
,因为yield*
运行迭代器并依次产生所有迭代器的值。如果传递生成器,则会发生完全相同的行为。
在您的情况下,您想让recurse
成为生成器,然后使用yield*
调用它:
function *preOrderGeneratorIteratorRecursive(rootNode) {
function *recurse(node) {
yield node;
for (let childNode of node.children)
yield* recurse(childNode);
}
yield* recurse(rootNode);
};
console.log("Pre-order generator iterator, recursive:");
for (let node of preOrderGeneratorIteratorRecursive(rootNode)) {
console.log(" '"+node.name+"'");
}
答案 1 :(得分:0)
问题在于,您尝试使用recurse
的{{1}}函数未被声明为生成器。这就是你得到语法错误的原因。它需要
yield
或只是
function preOrderGeneratorIteratorRecursive(rootNode) {
function* recurse(node) {
yield node;
for (let childNode of node.children)
yield* recurse(childNode);
}
return recurse(rootNode);
}