树形结构数据存储方案
Adjacency List:每一条记录存parent_id
Path Enumerations:每一条记录存整个tree path经过的node枚举
Nested Sets:每一条记录存 nleft 和 nright
Closure Table:维护一个表,所有的tree path作为记录进行保存。
各种方法的常用操作代价见下图
一般来说,数据量小,采用适合邻接表存储设计,简单灵活,而大部分情况下都不会有太大的数据,主要用于种类树、菜单树。
邻接表再程序中的使用:直接查询所有,然后构建树形结构数据。有序数据构建树,层级之间是有序的。可通过sql查询排序。
java list转tree
TreeNode接口
package klg.common.tree; import java.io.Serializable; import java.util.List; /** * * @author klguang * * @param <ID> */ public interface TreeNode<ID extends Serializable> { public ID getId(); public ID getParentId(); public <T extends TreeNode<ID>> void setChildren(List<T> children); }
TreeHelper工具类
package klg.common.tree; import java.io.Serializable; import java.util.ArrayList; import java.util.List; /** * * @author klguang * */ public class TreeHelper { /** * * @param parentID * null 为根节点 * @param nodeList * @param sort * @return */ public static <ID extends Serializable,T extends TreeNode<ID>> List<T> buildTree(ID parentID, List<T> nodeList) { // 根节点列表 List<T> list = new ArrayList<>(); // 顺序遍历节点列表,如果之前是有序的,那么构建树后同层级之间有序 for (int i=0; i<nodeList.size(); i++) { T node = nodeList.get(i); //递归入口, String.valueOf防止null值 if (String.valueOf(node.getParentId()).equals(String.valueOf(parentID))) { // parentID作为入口 List<T> children = buildTree(node.getId(), nodeList); node.setChildren(children); list.add(node); } } return list; } }
案例easyui tree
package klg.common.tree; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import javax.persistence.Access; import javax.persistence.AccessType; import javax.persistence.Column; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.MappedSuperclass; import javax.persistence.Transient; /** * * @author klguang * */ @MappedSuperclass @Access(AccessType.FIELD) public abstract class EasyUITreeNode<ID extends Serializable> implements Serializable, TreeNode<ID> { private static final long serialVersionUID = 850845227481354764L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private ID id; @Column(name = "parent_id") private ID parentId; @Column(name = "name", nullable = false) private String name; @Column(name = "icon_cls") private String iconCls; @Column(name = "state") private String state; @Column(name = "order_num") private Integer orderNum; @SuppressWarnings("rawtypes") @Transient List children = new ArrayList<>(); /** * easyui treegrid 需求格式 * * @return */ public String getText() { return this.name; } public ID getId() { return id; } public void setId(ID id) { this.id = id; } public ID getParentId() { return parentId; } public void setParentId(ID parentId) { this.parentId = parentId; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getIconCls() { return iconCls; } public void setIconCls(String iconCls) { this.iconCls = iconCls; } public String getState() { return state; } public void setState(String state) { this.state = state; } public Integer getOrderNum() { return orderNum; } public void setOrderNum(Integer orderNum) { this.orderNum = orderNum; } @SuppressWarnings("unchecked") public <T extends TreeNode<ID>> List<T> getChildren() { return children; } public<T extends TreeNode<ID>> void setChildren(List<T> children) { this.children = children; } }
使用方法
easyui tree实现类
public class Permission extends EasyUITreeNode<Long> { //fields }
构建树
public List<Permission> findAll(){ Sort sort = new Sort(Direction.ASC,"orderNum"); List<Permission> listData=permissionService.findList(sort); return TreeHelper.<Long,Permission>buildTree(null, listData); }