4

我被要求检索作为树节点的 descandant 的每个叶节点。我很快就想到我可以在一条线上完成这项工作!

public Set<TreeNode<E>> getLeaves() {
    return getChildrenStream().flatMap(n -> n.getChildrenStream()).collect(toSet());
}

乍一看很好,但StackOverflowExcepetion如果树深度达到〜10,它很快就遇到了,这是我无法接受的。后来我开发了一个没有递归和流的实现(但是我的大脑被了),但我仍然想知道是否有办法flatMap用流做递归,因为我发现如果不接触流内部就不可能这样做。它需要一个新的操作,就像RecursiveOps这样做,否则我必须将所有结果收集到Set每一步中,然后再对其进行操作Set

Set<TreeNode<E>> prev = new HashSet<>();
prev.add(this);
while (!prev.isEmpty()) {
    prev = prev.stream().flatMap(n -> n.getChildrenStream()).collect(toSet());
}
return prev;

不像看起来那么好。流意味着是一个管道。在添加终端操作之前,不会计算其结果和中间结果。上述做法显然违反了这一原则。并行化也不像流那么容易。我可以在不手动计算所有中间结果的情况下递归 flatMap 吗?

PS1:TreeNode 声明:

public class TreeNode<E> {
    // ...
    /**
     * Get a stream of children of the current node. 
     *
     */
    public Stream<TreeNode<E>> getChildrenStream(){
        // ...
    }

    public Set<TreeNode<E>> getLeaves() {
        // main concern
    }
}f
4

1 回答 1

0

不完全确定这是否是您感兴趣的事情:

public static Set<TreeNode<String>> getAllLeaves(TreeNode<String> treeNode) {
    final Stream<TreeNode<String>> childrenStream = treeNode.getChildrenStream();
    if (childrenStream == null) {
        return new HashSet<>();
    }

    Set<TreeNode<String>> ownLeaves = treeNode.getLeaves();
    ownLeaves.addAll(childrenStream.flatMap(stringTreeNode -> getAllLeaves(stringTreeNode).parallelStream())
            .collect(Collectors.toSet()));

    return ownLeaves;
}

开箱即用,我发现这种方法有一些不便之处。它确实为最后一次迭代返回了一个空 Set 并且它正在创建流,就像它一样flatMap。但是我相信这就是您正在寻找的东西,因为您正在考虑使用flatMap从哪里开始递归地创建连接的集合,而首先没有创建流。顺便说一句,我已经用 -1000 级别尝试过它,它仍然运行得非常快并且没有问题。

于 2016-05-28T15:30:18.570 回答