因此,我有一个基本的树结构,该结构由树节点组成,该树节点链接到具有父级和子级引用的其他树节点。我想创建一个方法,该方法返回一个 Stream,该流从叶节点流式传输到根节点或从根到叶。我已经实现了这个,但我正在寻找一种创建最少对象的解决方案。最好没有。这是我的代码:
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--);
}
}
}
这很好,但我的“问题”是,为每个流调用创建了很多对象。
流将被大量使用,所以我想尽可能避免创建对象。在没有流的情况下迭代树结构是一件简单的事情。现在我只使用流的映射方法。我可以只拥有一个接受消费者的方法,迭代深度并为每个节点调用消费者,不会创建任何对象,但我会失去所有流功能。看起来大概是这样的:
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应该实现或扩展一些接口/类吗?如果有什么不清楚的,请告诉我。
谢谢!
我不同意您对性能的担忧,但是,您的代码还有简化的空间,这可能会解决您的一些担忧作为副作用。
您犯了一个常见的错误,即从< code>Iterator实现开始,很可能是因为< code>Iterator接口很老而且广为人知。但是实现它很麻烦,而且如果您只是直接实现< code>Spliterator,则不需要将< code >迭代器包装在< code>Spliterator中,这只是一个很好的副作用:
public Stream<TreeNode<TNode>> streamFromLeaf() {
return StreamSupport.stream(new LeafFirstSpliterator<>(this), false);
}
static class LeafFirstSpliterator<TNode>
extends Spliterators.AbstractSpliterator<TreeNode<TNode>> {
private TreeNode<TNode> iNextNode;
LeafFirstSpliterator(TreeNode<TNode> leafNode) {
super(100, ORDERED|NONNULL);
iNextNode = leafNode;
}
public boolean tryAdvance(Consumer<? super TreeNode<TNode>> action) {
if(iNextNode==null) return false;
action.accept(iNextNode);
iNextNode=iNextNode.getParent();
return true;
}
}
对我来说,Spliterator
实现看起来更干净,至少它没什么好怕的,它可能允许更快的流遍历。您可以考虑重写 forEachRemaining
方法,因为它可以直接实现。
对于从根到叶的流,临时存储似乎是不可避免的,但如果是这样,请不要浪费时间进行低级编码,只需使用存储的内置流式处理功能:
public Stream<TreeNode<TNode>> streamFromRoot() {
ArrayDeque<TreeNode<TNode>> deque = new ArrayDeque<>();
for(TreeNode<TNode> n = this; n != null; n = n.getParent())
deque.addFirst(n);
return deque.stream();
}
不要使用流。使用您的替代方案,它有一个名称:访客模式。
流并不总是正确的方法,这是使用访问者模式的经典案例。
如果您一定要有一个流,让您的使用者收集列表中的节点,然后对其进行流处理,或者将使用者连接到迭代器的< code>next()方法(使用一些代码使其行为正常),并使用StreamSupport将其转换为流。
问题内容: 我有一个带有Node的图类,其中每个Node可以连接到其他节点: 我想复制整个图。第一次尝试,我尝试制作一个类似以下的复制构造函数: 因此,深度复制图形将是: 但这不起作用,因为这破坏了节点之间的连接关系。我想知道是否有人建议以一种简单的方式做到这一点?谢谢。 问题答案: 问题是您需要复制节点的身份,而不仅仅是节点的值。具体来说,当您复制某个节点时,您需要处理其所指节点的身份。这意味着
我不确定我的问题是出在代码的深度复制部分,还是我在将元素添加到原始列表时犯了错误。到目前为止我所掌握的是: ...其中与此相关联的测试用例是:
我试图创建一个JSON来表示任意深度和广度的层次结构,例如生物: 我想把它转换成这样的JSON: 这在博士后中可行吗? 到目前为止我已经试过了 但它失败了 有没有办法解决这个问题,或者其他解决方案可以让我成为我的好树?
问题内容: 我是Java的新手,我试图找到一种方法来在C语言中存储诸如结构之类的信息。例如,说我想让一名程序雇用员工。它将从用户那里获得一个名字,姓氏和ID号并将其存储起来。然后,用户可以根据条件查看该信息(例如,如果数据库有多于1名员工)。有没有人建议这样做的最佳方法? 问题答案: C中的结构就像Java中的类一样,功能更强大,因为Java中的类可以包含方法,而C ++可以。您创建一个新类。例如
主要内容:一个 XML 文档实例,XML 文档形成一种树结构,实例:,XML 文档实例XML 文档形成了一种树结构,它从"根部"开始,然后扩展到"枝叶"。 一个 XML 文档实例 XML 文档使用简单的具有自我描述性的语法: <?xml version="1.0" encoding="UTF-8"?> <note> <to>Tove</to> <from>Jani</from> <heading>Reminder</heading> <body>Don't forget me th
NowCoder 题目描述 从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。 解题思路 // java public int TreeDepth(TreeNode root) { return root == null ? 0 : 1 + Math.max(TreeDepth(root.left), TreeDepth(root.right));