JavaScript中的递归生成器

rob*_*bmj 20 javascript recursion generator ecmascript-6

我正在尝试为顺序遍历编写递归生成器.

class Tree {
  *inOrderTraversal() {
    function* helper(node) {
      if (node.left !== null) {
        // this line is executed, but helper is not being called
        helper(node.left); 
      }
      yield node.value;
      if (node.right !== null) {
        helper(node.right);
      }
    }

    for (let i of helper(this.root)) {
      yield i;
    }
  }
  // other methods omitted
}
Run Code Online (Sandbox Code Playgroud)

我这样称呼发电机:

const tree = new Tree();
tree.add(2);
tree.add(1);
tree.add(3);

for (let i of tree.inOrderTraversal()) {
    console.log(i); // only prints 2
}
Run Code Online (Sandbox Code Playgroud)

为什么发电机只能屈服2?为什么它至少没有产生1之前2

我怎样才能解决这个问题?

如果它有帮助,我正在使用babel来编译代码.

babel --optional runtime test.js | node

Ami*_*mit 25

问题不在于递归.你的函数确实递归地调用了它,它只是没有在外面产生值.当你调用helper()时,你得到一个迭代器作为返回值,但是你想要得到迭代器的迭代值.如果你想递归地屈服,你需要yield *.试试这样:

  * inOrderTraversal() {
    function* helper(node) {
      if (node.left !== null) {
        // this line is executed, but helper is not being called
        yield * helper(node.left); 
      }
      yield node.value;
      if (node.right !== null) {
        yield * helper(node.right);
      }
    }

    for (let i of helper(this.root)) {
      yield i;
    }
  }
Run Code Online (Sandbox Code Playgroud)

当你在它时,你可以用以下代码替换for循环:

yield * helper(this.root)
Run Code Online (Sandbox Code Playgroud)

  • @robbmj:`helper(node.left);`返回一个迭代器,但如果您不对返回值执行任何操作,那么它就会丢失。你必须以某种方式使用迭代器。我的意思是,再往下你还可以做“for (let i of helper(this.root)) {”,而不仅仅是“helper(node.left);”。这没什么不同。 (2认同)
  • 问题不在于递归.你的函数*做了*递归调用自己,它只是没有在外面产生值.当你调用`helper()`时,你得到一个迭代器作为返回值,但是你想要得到迭代器的迭代值,而这正是`yield*`的作用. (2认同)

Ber*_*rgi 5

helper(node.left);确实调用了函数并创建了生成器,但是生成器函数体永远不会执行,因为生成器永远不会被推进。要将其所有值转发到当前生成器,您可以使用yield*关键字,其工作方式与

for (let i of helper(this.root))
    yield i;
Run Code Online (Sandbox Code Playgroud)

你在你的inOrderTraversal方法中使用过。事实上,这也应该是一个yield*- 甚至更好,inOrderTraversal当它可以只是一个返回生成器的普通方法时,没有理由创建生成器函数:

class Tree {
  inOrderTraversal() {
    function* helper(node) {
      if (node.left !== null)
        yield* helper(node.left);
      yield node.value;
      if (node.right !== null)
        yield* helper(node.right);
    }

    return helper(this.root);
  }
  … // other methods
}
Run Code Online (Sandbox Code Playgroud)