在树中插入一个节点,每个节点有2个以上的子节点

时间:2018-02-03 06:51:22

标签: java algorithm recursion data-structures tree

我有一个父子关系的数据库表,任何父级都可以有任意数量的子级,但根级别只有1个父级。数据如下所示:

    TagID   ParentTagID   TagName
-------------------------------
    1        null          a
    2        1             b
    3        1             c
    4        1             d
    5        2             e
    6        4             f
    7        2             g

我想以树格式获取java中的记录。虽然我可以使用下面的SQL在SQL级别本身实现这一点但我想从数据库中提取数据并在java级别执行处理,以便java和SQL之间的连接可以是最短的持续时间,以避免任何延迟数据库方面。

with cte as
(
  select * from TagValue
  where ParentTagID is null

  union all

  select s.* from TagValue s
  join cte c on s.ParentTagID = c.TagID
)
select * from cte

使用Java从其他有用的链接获取帮助,我创建了一个树,如下所示:

public class MyTreeNode<T> {
    private T data = null;
    private List<MyTreeNode<T>> children = new ArrayList<MyTreeNode<T>>();
    private MyTreeNode<T> parent = null;

    public MyTreeNode(T data) {
        this.data = data;
    }

    public void addChild(MyTreeNode<T> child) {
        child.setParent(this);
        this.children.add(child);
    }

    public void addChild(T data) {
        MyTreeNode<T> newChild = new MyTreeNode<T>(data);
        newChild.setParent(this);
        children.add(newChild);
    }

    public void addChildren(List<MyTreeNode<T>> children) {
        for (MyTreeNode<T> t : children) {
            t.setParent(this);
        }
        this.children.addAll(children);
    }

    public List<MyTreeNode<T>> getChildren() {
        return children;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    private void setParent(MyTreeNode<T> parent) {
        this.parent = parent;
    }

    public MyTreeNode<T> getParent() {
        return parent;
    }
}

在此树中插入对象时,我可以使用以下代码:

MyTreeNode<Integer> root = new MyTreeNode<Integer>(1);

MyTreeNode<Integer> child1 = new MyTreeNode<Integer>(2);
child1.addChild(3);
child1.addChild(4);

MyTreeNode<Integer> child2 = new MyTreeNode<Integer>(5);
child2.addChild(6);

root.addChild(child1);
root.addChild(child2);
root.addChild(7);

root.addChildren(Arrays.asList(new MyTreeNode<Integer>(8),
        new MyTreeNode<Integer>(9), new MyTreeNode<Integer>(10)));

但这是一个静态代码,而标签的数量可能是动态的。我需要一个递归解决方案来根据ParentTag值查找节点,然后将新标签插入其子节点。有这样的递归解决方案吗?如果Java 1.8中有任何其他开箱即用的数据结构来执行此操作,那么这也很有用。

1 个答案:

答案 0 :(得分:1)

给定ResultSet,您希望自然地构建树结构,如下所示:

while (... has more rows ...) {
    addNode(rs.ParentTagID, rs.TagID);

您需要某种类型的容器来存储您的树节点。您可以使用List但是在构建树时性能会受到影响;添加子项需要查找其父项,列表不提供快速方法。一张地图 但是提供O(1)查找。

辅助方法 addNode 将使树保持圆满:找到父级,并相应地添加子级。

总之,您正在寻找的动态方法是迭代结果集,并重复调用addNode()传递parentId和childId(存储在数据库中)。根节点是一种特殊情况(其中parentId = null或0),由addNode()处理。

对MyTreeNode稍作修改以返回对象(添加子对象时);它过去属于void。

以下是一些显示此方法的示例代码。

public class MutipleTreeNode {

static Map<Integer, MyTreeNode<Integer>> nodeMap = new HashMap<>();

public static void main(String[] args) {

    // Here you would process your result set
    // Rather than simulate a result set, I just build some nodes manually
    addNode(0, 1);  // Root
    addNode(1, 2);
    addNode(1, 3);
    addNode(1, 4);
    addNode(2, 5);
    addNode(2, 7);
    addNode(4, 6);

    printTree();

}

private static void printTree() {
    for (MyTreeNode<Integer> node : nodeMap.values()) {
        if (node.getParent() == null)
            System.out.print("Root node: ");
        System.out.println(node.getData()+"; children="+node.getChildren());
    }

}

private static void addNode(int parentId, int childId) {
    MyTreeNode<Integer> childNode, parentNode;
    if (nodeMap.isEmpty())
        childNode = new MyTreeNode<Integer>(childId);
    else {
        parentNode = nodeMap.get(parentId);
        childNode = parentNode.addChild(childId);
    }
    nodeMap.put(childId, childNode);
}

public static class MyTreeNode<T> {
    private T data = null;
    private List<MyTreeNode<T>> children = new ArrayList<MyTreeNode<T>>();
    private MyTreeNode<T> parent = null;

    public MyTreeNode(T data) {
        this.data = data;
    }

    public void addChild(MyTreeNode<T> child) {
        child.setParent(this);
        this.children.add(child);
    }

    public MyTreeNode<T> addChild(T data) {
        MyTreeNode<T> newChild = new MyTreeNode<T>(data);
        newChild.setParent(this);
        children.add(newChild);
        return newChild;
    }

    public void addChildren(List<MyTreeNode<T>> children) {
        for (MyTreeNode<T> t : children) {
            t.setParent(this);
        }
        this.children.addAll(children);
    }

    public List<MyTreeNode<T>> getChildren() {
        return children;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    private void setParent(MyTreeNode<T> parent) {
        this.parent = parent;
    }

    public MyTreeNode<T> getParent() {
        return parent;
    }

    @Override
    public String toString() {
        return "[data=" + data + "]";
    }
}
}

创建输出:

Root node: 1; children=[[data=2], [data=3], [data=4]]
2; children=[[data=5], [data=7]]
3; children=[]
4; children=[[data=6]]
5; children=[]
6; children=[]
7; children=[]