我有两棵树,例如:
<example>
root root2 root after merge
A0 A0 A0
| | |
A1 A1 A1
/ \ / \ / / \ \
A2 A3 A4 A5 A2 A3 A4 A5
&#13;
我的班级节点:所有的getter和setter:
public class Node {
private String data;
private Node parent;
private List<Node> children;
public Node(String data) {
this.data = data;
parent = null;
children = new ArrayList<Node>(); //Empty list of children
}
}
这段代码我试过但执行不正确它是重复的A1
private static void CompareTree(Node root2) {
if(root==null) {
root=root2;
}
else {
for (Node child : root.getChildren()) {
for ( Node child1: root2.getChildren()){
if( child.equals(child1))
// CompareTree(child1);
child.addChild(child1);
}
}
}
}
如果有人能帮助我,我将非常感激。
提前谢谢。
答案 0 :(得分:0)
一个主要问题是如何比较节点:n1.equals(n2)
。但是你从未覆盖equals
中的Node
- 方法,因此将使用java.lang.Object
提供的默认值,其行为方式如下:
类Object的equals方法实现了对象上最具辨别力的等价关系;也就是说,对于任何非空引用值x和y,当且仅当x和y引用同一对象时,此方法才返回true(x == y的值为true)。
这意味着比较不会看data
(我假设是相关字段),而只是比较引用。您需要按以下方式覆盖equals
中的Node
,以便为equals
提供预期的行为:
class Node{
... // variables and constructor
@Override
public boolean equals(Object o){
return (o != null) && (o instanceof Node) && (data.equals(((Node) o).data);
}
@Override
public int hashCode(){
return Objects.hash(data);
}
}
(请注意,上述实现假定Node#data
永远不会是null
。如果是这种情况,请相应地重写代码!)
合并操作本身:
对于static
方法,我建议为每个Node
使用一个参数,并按以下方式工作,因为递归方法最简单:
static void merge(Node a, Node b){
List<Node> toMerge = new ArrayList<>(a.getChildren()).retainAll(b.getChildren());
List<Node> toAdd = new ArrayList<>(b.getChildren()).removeAll(a.getChildren());
for(Node n : toMerge)
merge(n, b.getChildren().get(b.getChildren().indexOf(n)));
for(Node n : toAdd)
a.addChild(n.deepCopy());
}
class Node{
... //variables, constructor, equals, etc.
public Node deepCopy(){
Node n = new Node(data);
for(Node c : children)
n.addChild(c.deepCopy());
return n;
}
}
以上代码的工作方式如下:
toMerge
包含来自b
的所有子节点,data
(集合交集)中存在等效a
的子节点,toAdd
包含所有子节点在b
(设置差异)中没有data
个子节点的a
节点。这两个集是互补的,因此没有节点丢失而且没有节点被添加。对于需要合并的所有节点,merge
递归地应用于a
中的节点,并且它在b
中等效。对于仅出现在b
中的所有节点,将该节点的深层副本添加为a
的子节点(深层副本是从特定节点开始的整个树结构的副本)。 / p>