遍历表生成树列表

时间:2022-06-15 22:16:37
   最近正在搞遍历表,然后在前台生成动态的树,想用递归来实现,但是自己一直写不出,陷入了思维混乱状态,特此发帖,寻求帮助
   我想循环遍历下面这张表的内容
    遍历表生成树列表

最终我想要
打印输出这样的结果:

一级子菜单
------一级子菜单1
------一级子菜单2
二级子菜单
------二级子菜单
-------------------二级下一级子菜单

请各位大侠不吝赐教!!!!

8 个解决方案

#1


你的思维似乎有点混乱。
如果是Web项目的话,百度一下“hibernate自关联”,有很多代码供你参考,而且不用递归。
如果你想体现程序的思想,应该是普通树的先序遍历吧?
普通树的逻辑结构是这样的:
遍历表生成树列表
但在计算机内部的存储结构却是这样的:
遍历表生成树列表
所以很容易写出以下的代码:


import org.junit.Test;

/**
 * 普通树的节点
 *
 */
class TreeNode{

/**
 * 数据域
 */
private String data;

/**
 * 第一个孩子
 */
private TreeNode firstCh;

/**
 * 下一个兄弟
 */
private TreeNode nextSib;
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}

public TreeNode getFirstCh() {
return firstCh;
}
public void setFirstCh(TreeNode firstCh) {
this.firstCh = firstCh;
}
public TreeNode getNextSib() {
return nextSib;
}
public void setNextSib(TreeNode nextSib) {
this.nextSib = nextSib;
}
public TreeNode(String data) {
super();
this.data = data;
}
public TreeNode(String data, TreeNode firstCh, TreeNode nextSib) {
super();
this.data = data;
this.firstCh = firstCh;
this.nextSib = nextSib;
}
public TreeNode() {
super();
}
@Override
public String toString() {
return "TreeNode [data=" + data + "]";
}


}
public class Tree {

/**
 * 静态数组  用于查表
 */
public static final String[] array={"--","----","------","--------","----------"};
public void outputTree(TreeNode root){
this.preOrder(root, 1);
}
/**
 *先序遍历一棵普通树
 *1、遍历p自身
 *2、递归遍历p的第一个孩子,层数+1
 *3、递归遍历p的下一个兄弟,层数不变
 */
public void preOrder(TreeNode node,int ceng){
if(node!=null){
System.out.println(array[ceng-1]+node.getData());
this.preOrder(node.getFirstCh(),ceng+1);
this.preOrder(node.getNextSib(), ceng);
}

}
@Test
public void test(){
TreeNode node1=new TreeNode("三级菜单3");
TreeNode node2=new TreeNode("三级菜单2");
node2.setNextSib(node1);
TreeNode node3=new TreeNode("三级菜单1");
node3.setNextSib(node2);
TreeNode node4=new TreeNode("二级菜单2");
TreeNode node5=new TreeNode("二级菜单1", node3, node4);
TreeNode node6=new TreeNode("一级菜单");
node6.setFirstCh(node5);
this.outputTree(node6);
}
}


其中,preOrder()函数是一个算法框架,你可以把:
System.out.println(array[ceng-1]+node.getData());改成你自己想要的业务逻辑。

#2


运行结果:

--一级菜单
----二级菜单1
------三级菜单1
------三级菜单2
------三级菜单3
----二级菜单2

#3


数据不要一次性读取出来,动态的点击某个结点后,再读取出它的子结点。
这样SQL语句好写,性能也高。

#4


因为我的树列表数据不是特别多,所以想一次性遍历出来,现在就是在递归的时候出现问题了,自己的思路也不是很清晰,所以想请教各位大侠。
我的是JAVAWeb项目

#5


如果仅仅只是打印 。 根据url排序就可以了。


#6


我主要是想在前台用easyui-tree来展示,希望后台返回下面的格式

<ul id="tree" class="easyui-tree" data-options="animate:false,dnd:false">
<li>
<span>系统功能</span>
<ul>
<li data-options="state:'closed'">
<span>用户管理</span>
<ul>
<li>
<span>
<a onclick="addTab('信息管理','userInit.json');">信息管理</a>
</span>
</li>
<li>
<span>角色管理</span>
</li>
</ul>
</li>
<li>
<span>系统参数管理</span>
</li>
</ul>
</li>
</ul>

#7


递归查询的时候,SQL里用in子句:
如select id in (parent_id_1, parent_id_2,....)
这里的parent_id_x是在Java里用字符串排起来的
在JAVA里用递归查询,而不是在SQL语句里用递归。

#8


供上马士兵的Hibernate的自关联源码,你参考一下:

package com.bjsxt.hibernate;

import java.util.Map;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

public class HibernateTreeTest {
private static SessionFactory sessionFactory;

@BeforeClass
public static void beforeClass() {
new SchemaExport(new AnnotationConfiguration().configure()).create(false, true);
sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
}
@AfterClass
public static void afterClass() {
sessionFactory.close();
}

@Test
public void testSave() {
Org o = new Org();
o.setName("总公司");
Org o1 = new Org();
o1.setName("分公司1");
Org o2 = new Org();
o2.setName("分公司2");
Org o11 = new Org();
o11.setName("分公司1下部门1");
Org o12 = new Org();
o12.setName("分公司1下部门2");

o.getChildren().add(o1);
o.getChildren().add(o2);
o1.getChildren().add(o11);
o1.getChildren().add(o12);
o11.setParent(o1);
o12.setParent(o1);
o1.setParent(o);
o2.setParent(o);


Session session = sessionFactory.openSession();
session.beginTransaction();
session.save(o);

session.getTransaction().commit();
session.close();
}
@Test
public void testLoad() {
testSave();
Session session = sessionFactory.openSession();
session.beginTransaction();
Org o = (Org)session.load(Org.class, 1);
print(o, 0);
session.getTransaction().commit();
session.close();

}
//这个递归一定要理解!
private void print(Org o, int level) {
String preStr = "";
for(int i=0; i<level; i++) {
preStr += "----";
}
System.out.println(preStr + o.getName());
for(Org child : o.getChildren()) {
print(child, level+1);
}
}
@Test
public void testSchemaExport() {
new SchemaExport(new AnnotationConfiguration().configure()).create(false, true);
}


public static void main(String[] args) {
beforeClass();
}
}



下面是实体类:

package com.bjsxt.hibernate;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;

@Entity
public class Org {
private int id;
private String name;
private Set<Org> children = new HashSet<Org>();
private Org parent;
@Id
@GeneratedValue
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@OneToMany(cascade=CascadeType.ALL, mappedBy="parent")
public Set<Org> getChildren() {
return children;
}
public void setChildren(Set<Org> children) {
this.children = children;
}

@ManyToOne
@JoinColumn(name="parent_id")
public Org getParent() {
return parent;
}
public void setParent(Org parent) {
this.parent = parent;
}
}
你根据这个“官方的自关联”修改修改,和前台结合结合。

#1


你的思维似乎有点混乱。
如果是Web项目的话,百度一下“hibernate自关联”,有很多代码供你参考,而且不用递归。
如果你想体现程序的思想,应该是普通树的先序遍历吧?
普通树的逻辑结构是这样的:
遍历表生成树列表
但在计算机内部的存储结构却是这样的:
遍历表生成树列表
所以很容易写出以下的代码:


import org.junit.Test;

/**
 * 普通树的节点
 *
 */
class TreeNode{

/**
 * 数据域
 */
private String data;

/**
 * 第一个孩子
 */
private TreeNode firstCh;

/**
 * 下一个兄弟
 */
private TreeNode nextSib;
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}

public TreeNode getFirstCh() {
return firstCh;
}
public void setFirstCh(TreeNode firstCh) {
this.firstCh = firstCh;
}
public TreeNode getNextSib() {
return nextSib;
}
public void setNextSib(TreeNode nextSib) {
this.nextSib = nextSib;
}
public TreeNode(String data) {
super();
this.data = data;
}
public TreeNode(String data, TreeNode firstCh, TreeNode nextSib) {
super();
this.data = data;
this.firstCh = firstCh;
this.nextSib = nextSib;
}
public TreeNode() {
super();
}
@Override
public String toString() {
return "TreeNode [data=" + data + "]";
}


}
public class Tree {

/**
 * 静态数组  用于查表
 */
public static final String[] array={"--","----","------","--------","----------"};
public void outputTree(TreeNode root){
this.preOrder(root, 1);
}
/**
 *先序遍历一棵普通树
 *1、遍历p自身
 *2、递归遍历p的第一个孩子,层数+1
 *3、递归遍历p的下一个兄弟,层数不变
 */
public void preOrder(TreeNode node,int ceng){
if(node!=null){
System.out.println(array[ceng-1]+node.getData());
this.preOrder(node.getFirstCh(),ceng+1);
this.preOrder(node.getNextSib(), ceng);
}

}
@Test
public void test(){
TreeNode node1=new TreeNode("三级菜单3");
TreeNode node2=new TreeNode("三级菜单2");
node2.setNextSib(node1);
TreeNode node3=new TreeNode("三级菜单1");
node3.setNextSib(node2);
TreeNode node4=new TreeNode("二级菜单2");
TreeNode node5=new TreeNode("二级菜单1", node3, node4);
TreeNode node6=new TreeNode("一级菜单");
node6.setFirstCh(node5);
this.outputTree(node6);
}
}


其中,preOrder()函数是一个算法框架,你可以把:
System.out.println(array[ceng-1]+node.getData());改成你自己想要的业务逻辑。

#2


运行结果:

--一级菜单
----二级菜单1
------三级菜单1
------三级菜单2
------三级菜单3
----二级菜单2

#3


数据不要一次性读取出来,动态的点击某个结点后,再读取出它的子结点。
这样SQL语句好写,性能也高。

#4


因为我的树列表数据不是特别多,所以想一次性遍历出来,现在就是在递归的时候出现问题了,自己的思路也不是很清晰,所以想请教各位大侠。
我的是JAVAWeb项目

#5


如果仅仅只是打印 。 根据url排序就可以了。


#6


我主要是想在前台用easyui-tree来展示,希望后台返回下面的格式

<ul id="tree" class="easyui-tree" data-options="animate:false,dnd:false">
<li>
<span>系统功能</span>
<ul>
<li data-options="state:'closed'">
<span>用户管理</span>
<ul>
<li>
<span>
<a onclick="addTab('信息管理','userInit.json');">信息管理</a>
</span>
</li>
<li>
<span>角色管理</span>
</li>
</ul>
</li>
<li>
<span>系统参数管理</span>
</li>
</ul>
</li>
</ul>

#7


递归查询的时候,SQL里用in子句:
如select id in (parent_id_1, parent_id_2,....)
这里的parent_id_x是在Java里用字符串排起来的
在JAVA里用递归查询,而不是在SQL语句里用递归。

#8


供上马士兵的Hibernate的自关联源码,你参考一下:

package com.bjsxt.hibernate;

import java.util.Map;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

public class HibernateTreeTest {
private static SessionFactory sessionFactory;

@BeforeClass
public static void beforeClass() {
new SchemaExport(new AnnotationConfiguration().configure()).create(false, true);
sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
}
@AfterClass
public static void afterClass() {
sessionFactory.close();
}

@Test
public void testSave() {
Org o = new Org();
o.setName("总公司");
Org o1 = new Org();
o1.setName("分公司1");
Org o2 = new Org();
o2.setName("分公司2");
Org o11 = new Org();
o11.setName("分公司1下部门1");
Org o12 = new Org();
o12.setName("分公司1下部门2");

o.getChildren().add(o1);
o.getChildren().add(o2);
o1.getChildren().add(o11);
o1.getChildren().add(o12);
o11.setParent(o1);
o12.setParent(o1);
o1.setParent(o);
o2.setParent(o);


Session session = sessionFactory.openSession();
session.beginTransaction();
session.save(o);

session.getTransaction().commit();
session.close();
}
@Test
public void testLoad() {
testSave();
Session session = sessionFactory.openSession();
session.beginTransaction();
Org o = (Org)session.load(Org.class, 1);
print(o, 0);
session.getTransaction().commit();
session.close();

}
//这个递归一定要理解!
private void print(Org o, int level) {
String preStr = "";
for(int i=0; i<level; i++) {
preStr += "----";
}
System.out.println(preStr + o.getName());
for(Org child : o.getChildren()) {
print(child, level+1);
}
}
@Test
public void testSchemaExport() {
new SchemaExport(new AnnotationConfiguration().configure()).create(false, true);
}


public static void main(String[] args) {
beforeClass();
}
}



下面是实体类:

package com.bjsxt.hibernate;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;

@Entity
public class Org {
private int id;
private String name;
private Set<Org> children = new HashSet<Org>();
private Org parent;
@Id
@GeneratedValue
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@OneToMany(cascade=CascadeType.ALL, mappedBy="parent")
public Set<Org> getChildren() {
return children;
}
public void setChildren(Set<Org> children) {
this.children = children;
}

@ManyToOne
@JoinColumn(name="parent_id")
public Org getParent() {
return parent;
}
public void setParent(Org parent) {
this.parent = parent;
}
}
你根据这个“官方的自关联”修改修改,和前台结合结合。