Java 在树中插入每个节点有两个子节点以上的节点
我有一个具有父子关系的数据库表,任何父级都可以有任意数量的子级,但在根级别只有一个父级。数据如下所示:Java 在树中插入每个节点有两个子节点以上的节点,java,algorithm,recursion,data-structures,tree,Java,Algorithm,Recursion,Data Structures,Tree,我有一个具有父子关系的数据库表,任何父级都可以有任意数量的子级,但在根级别只有一个父级。数据如下所示: TagID ParentTagID TagName ------------------------------- 1 null a 2 1 b 3 1 c 4 1 d 5 2
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{
私有T数据=null;
private List children=new ArrayList();
private MyTreeNode parent=null;
公共MyTreeNode(T数据){
这个数据=数据;
}
public void addChild(MyTreeNode child){
child.setParent(this);
this.children.add(child);
}
公共void addChild(T数据){
MyTreeNode newChild=新MyTreeNode(数据);
newChild.setParent(this);
添加(newChild);
}
公共子项(列出子项){
用于(MyTreeNode t:儿童){
t、 setParent(本);
}
this.children.addAll(children);
}
公共列表getChildren(){
返回儿童;
}
公共T getData(){
返回数据;
}
公共无效设置数据(T数据){
这个数据=数据;
}
私有void setParent(MyTreeNode父级){
this.parent=parent;
}
公共MyTreeNode getParent(){
返回父母;
}
}
在此树中插入对象时,我可以使用以下代码:
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)));
mytreenoderoot=新的MyTreeNode(1);
MyTreeNode child1=新MyTreeNode(2);
child1.addChild(3);
child1.addChild(4);
MyTreeNode child2=新MyTreeNode(5);
child2.addChild(6);
root.addChild(child1);
root.addChild(child2);
root.addChild(7);
root.addChildren(Arrays.asList)(新的MyTreeNode(8),
新MyTreeNode(9),新MyTreeNode(10));
但这是一个静态代码,而标记的数量可能是动态的。我需要一个递归解决方案,根据ParentTag值找到一个节点,然后插入新标记作为其子节点。有没有递归解决方案可以做到这一点?如果Java 1.8中有任何其他现成的数据结构来执行此操作,这也会很有用。给定结果集,您希望自然构建树结构,如下所示:
while (... has more rows ...) {
addNode(rs.ParentTagID, rs.TagID);
您需要某种类型的容器来存储树节点。您可以使用列表,但是在构建树时性能会受到影响;添加子级需要查找其父级,而列表并没有提供快速的方法。地图
但是提供了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 + "]";
}
}
}
我可能会在数据库中处理这个问题。是什么让您认为在Java中这样做会更有效?静态
addChild(MyTreeNode子级,MyTreeNode父级)不是吗
给你你需要的吗?@TimBiegeleisen……你说得对,但我们计划将所有数据处理从数据库迁移到javaside@c0der...that是正确的,但是我应该如何遍历现有树,根据ParentTag查找节点,以添加新节点作为其子节点?我是否应该创建一个列表,并在每次需要插入新对象以查找parentnode时反复遍历该列表?感谢您的分享,您的解决方案更加优化,因为在O(1)的HashMap中进行了迭代
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=[]