在相同的节点上合并树

时间:2018-03-09 12:28:28

标签: java

我有两棵树,例如:



                                      <example>
   root           root2                  root after merge
     A0            A0                        A0
     |              |                        |
     A1             A1                       A1
    / \            /  \                  /  /   \  \  
   A2 A3          A4  A5               A2 A3   A4  A5
&#13;
&#13;
&#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);
            }
        }
    }
}

如果有人能帮助我,我将非常感激。

提前谢谢。

1 个答案:

答案 0 :(得分:0)

一个主要问题是如何比较节点:n1.equals(n2)。但是你从未覆盖equals中的Node - 方法,因此将使用java.lang.Object提供的默认值,其行为方式如下:

  

类Object的equals方法实现了对象上最具辨别力的等价关系;也就是说,对于任何非空引用值x和y,当且仅当x和y引用同一对象时,此方法才返回true(x == y的值为true)。

Source

这意味着比较不会看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>