JavaScript中的递归生成器

时间:2015-09-25 19:47:11

标签: 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
}

我这样称呼发电机:

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
}

为什么生成器只能产生2?为什么在1之前至少不会产生2

我该如何解决这个问题?

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

babel --optional runtime test.js | node

2 个答案:

答案 0 :(得分:22)

问题不在于递归。你的函数 以递归方式调用自身,它只是没有产生外部的值。当你调用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;
    }
  }

虽然您正在使用它,但您可以将for循环替换为:

yield * helper(this.root)

答案 1 :(得分:4)

helper(node.left);会调用该函数并创建生成器,但永远不会执行生成器函数体,因为生成器永远不会前进。要将其所有值转发到当前生成器,您可以使用yield* keyword,它就像

一样工作
for (let i of helper(this.root))
    yield i;

您已在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
}