以下是无法返回正确的子节点,即使它实际上是在树的上方找到了孩子。它似乎在发现后让孩子掉线,广告继续搜索树的其余部分。
private Node<K, V> getNode(K key, ArrayList<Node<K, V>> children){
if (children == null) return null;
if (root.getKey().equals(key)) return root;
for (Node<K, V> child : children) {
if (child.getKey().equals(key)) return child;
getNode(key, child.getChildren());
}
return null;
}
我用以下代码测试了它:
Tree<Integer, String> tree = new Tree<>(1, "1");
tree.addChild(1, new Node<>(2, "2"));
tree.addChild(1, new Node<>(3, "3"));
tree.addChild(1, new Node<>(4, "4"));
tree.addChild(2, new Node<>(5, "5"));
System.out.println(tree.addChild(5, new Node<>(6, "6")));
System.out.println(tree.addChild(5, new Node<>(7, "7")));
但是,控制台两次输出false
,即使它应该是true
。无法找到具有5
键的子项,即使我在树中添加了一个。
答案 0 :(得分:1)
问题在于,当您在子树中查找子项时,忽略返回值:
if (child.getKey().equals(key))
{
// This is fine
return child;
}
else
{
// This is bad: you ignore the return value.
getNode(key, child.getChildren());
}
要修复,请捕获返回值,如果不是null
则返回,如下所示:
if (child.getKey().equals(key))
{
return child;
}
else
{
Node<K, V> res = getNode(key, child.getChildren());
if (res != null) {
return res;
}
}
此外,当代码存储在根目录中时,您的代码将会错过这种情况,并且根目录中没有子代,因为root.getKey().equals(key)
不在没有子代的节点上完成孩子。
答案 1 :(得分:1)
在return getNode(key, child.getChildren())
语句中写else
。它是使用递归的方式。
....
else
{
return getNode(key, child.getChildren());
}
答案 2 :(得分:1)
在重新格式化工作之后,我将您的代码重构为更易读的形式。虽然差别很大,但以下内容在逻辑上与您的代码完全相同:
private Node<K, V> getNode(K key, ArrayList<Node<K, V>> children){
if (children == null) return null;
if (root.getKey().equals(key)) return root;
for (Node<K,V> child : children) {
if (child.getKey().equals(key)) return child;
getNode(key, child.getChildren());
}
return null;
}
现在,我们可以挑选代码并修复它。
第一个问题是,您在方法前面没有javadoc注释,记录其参数并使用@param
和@return
返回值。这是你需要解决的问题。
其次,此方法应该作为Node
类的类方法实现,并且应该是public
。那就是:
class Node<K,V> {
// ... whatever else this class has in it ...
public K getKey() { /* ... stuff ... */ }
ArrayList<Node<K,V>> children = new ArrayList<>();
public Node<K, V> getNode(K key){
if (children == null) return null;
if (key.equals(this.getKey())) return this;
for (Node<K,V> child : children) {
if (child.getKey().equals(key)) return child;
child.getNode(key);
}
return null;
}
}
此外,由于我们现在保证children
始终被初始化,并且完全在我们的控制之下,我们可以摆脱伪造的null
检查。
public Node<K, V> getNode(K key){
if (key.equals(this.getKey())) return this;
for (Node<K,V> child : children) {
if (child.getKey().equals(key)) return child;
child.getNode(key);
}
return null;
}
现在,你正在冗余地检查孩子们。由于getNode()
已经检查this
是否是正确的节点,因此没有理由单独检查当前节点的每个子节点:
public Node<K, V> getNode(K key){
if (key.equals(this.getKey())) return this;
for (Node<K,V> child : children)
child.getNode(key);
return null;
}
现在我们已经摆脱了这么多代码,问题实际上应该是相当明显的:上层方法实际上从未通过搜索子节点对节点进行任何操作。一个简单的改变足以解决这个问题:
public Node<K, V> getNode(K key){
if (key.equals(this.getKey())) return this;
for (Node<K,V> child : children){
Node<K,V> result = child.getNode(key);
if(result != null) return result;
}
return null;
}
请注意,我们不应该检查孩子是否null
。这应该由我们公开的用于添加新值的方法来处理,我们永远不应该将外部节点添加到树中:
public boolean put(K key, V value){
children.add(new Node<>(key, value));
}
还有一件事:根本不需要单独的Tree
课程 !你不应该有一个,它的所有功能都应该完全存在于节点类中。理想情况下,根节点 树。