树形结构数据存储方案
Adjacency List:每一条记录存parent_id
Path Enumerations:每一条记录存整个tree path经过的node枚举
Nested Sets:每一条记录存 nleft 和 nright
Closure Table:维护一个表,所有的tree path作为记录进行保存。
各种方法的常用操作代价见下图
![fcf1ab401ae938be41f4a20b01fc38d0_b.jpg](https://i-blog.csdnimg.cn/blog_migrate/c9c9d80f33a49cd9eec528e275682686.png)
![](https://i-blog.csdnimg.cn/blog_migrate/9d95a08bbdc53c0a8bcc672f4609f6b7.png)
一般来说,数据量小,采用适合邻接表存储设计,简单灵活,而大部分情况下都不会有太大的数据,主要用于种类树、菜单树。
邻接表再程序中的使用:直接查询所有,然后构建树形结构数据。有序数据构建树,层级之间是有序的。可通过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); }