所以,我有一个基本的树结构,它由树节点和父节点和子节点的引用链接到其他树节点组成。我想创建一个方法,它返回一个从叶节点到根节点或从根到叶的流。我已经实现了这一点,但我正在寻找一个解决方案,创建最少量的对象。优选没有。这里是我的代码:在Tree结构上创建深度流
public class TreeNode<TNode> {
private TNode iValue;
private TreeNode<TNode> iParentNode = null;
private List<TreeNode<TNode>> iChildren = new ArrayList<>();
public TreeNode(TNode value) {
this(value, null);
}
private TreeNode(TNode value, TreeNode<TNode> parentNode) {
iValue = value;
iParentNode = parentNode;
}
public Stream<TreeNode<TNode>> streamFromLeaf() {
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(new LeafFirstIterator(this), Spliterator.SIZED),
false);
}
public Stream<TreeNode<TNode>> streamFromRoot() {
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(new RootFirstIterator(this), Spliterator.SIZED),
false);
}
public TNode getValue() {
return iValue;
}
public TreeNode<TNode> getParent() {
return iParentNode;
}
public TreeNode<TNode> addChild(TNode childValue) {
TreeNode<TNode> childNode = new TreeNode<TNode>(childValue, iNodeNameFunction, this);
iChildren.add(childNode);
return childNode;
}
public boolean isLeaf() {
return iChildren.size() == 0;
}
public boolean isRoot() {
return iParentNode == null;
}
public List<TreeNode<TNode>> getChildren() {
return iChildren;
}
class LeafFirstIterator implements Iterator<TreeNode<TNode>> {
private TreeNode<TNode> iNextNode;
LeafFirstIterator(TreeNode<TNode> leafNode) {
iNextNode = leafNode;
}
@Override
public boolean hasNext() {
return iNextNode != null;
}
@Override
public TreeNode<TNode> next() {
TreeNode<TNode> current = iNextNode;
iNextNode = current.getParent();
return current;
}
}
class RootFirstIterator implements Iterator<TreeNode<TNode>> {
private List<TreeNode<TNode>> iNodes = new ArrayList<>();
private int iNextIndex;
RootFirstIterator(TreeNode<TNode> leafNode) {
TreeNode<TNode> currentNode = leafNode;
while (currentNode != null) {
iNodes.add(currentNode);
currentNode = currentNode.getParent();
}
iNextIndex = iNodes.size() - 1;
}
@Override
public boolean hasNext() {
return iNextIndex >= 0;
}
@Override
public TreeNode<TNode> next() {
return iNodes.get(iNextIndex--);
}
}
}
这工作得很好,但我的“问题”是,大量的对象是为每一个流调用。
- StreamSupport.stream创造了新的ReferencePipeline
- Spliterators.spliteratorUnknownSize创造了新的IteratorSpliterator
- 创建我自己的迭代器实现传递给Spliterator
- RootFirstIterator创造了新的ArrayList
流是会被大量使用,所以我想尽可能避免创建对象。迭代没有流的树结构是一件简单的事情。现在我只使用流的映射方法。我只需要一个方法,它需要一个Consumer,迭代深度并为每个节点调用消费者,并且不会创建对象,但是我会丢失所有流功能。这看起来像这样:
public void iterateUp(Consumer<TreeNode<TNode>> consumer) {
doIterateUp(this, consumer);
}
public static <T> void doIterateUp(TreeNode<T> node, Consumer<TreeNode<T>> consumer) {
if (node == null)
return;
consumer.accept(node);
doIterateUp(node.getParent(), consumer);
}
并从根重复下来将会一样简单。
对此的任何想法?我是否以这种错误的方式去做? TreeNode应该实现还是扩展一些接口/类?如果有什么不清楚,请告诉我。
谢谢!
这不是必须的,但会非常好。我的另一个想法是将一个过滤器谓词,一个map函数和一个消费者传递给迭代方法,我会得到部分流类似的func,并且不会创建任何对象。但对我来说似乎有点难看。将节点收集到列表和流式传输中,我认为非常类似的对象创建方式对我的解决方案是明智的,实际上可能会更好一些。 –