Java中id,pid格式数据转树和森林结构工具类实现
作者:小熊vip 时间:2021-07-10 08:46:17
树形结构很多地方都有应用,比如我们在构造网站后台的授权限树的时候,再比如我们在设计多级留言的时候、还有分类等等。
有些时候我们的树形结构并不需要过多设计,这是因为我们的很多时候对这棵树的要求不高(两层、三层就行了),这时候我们很容易的会按照层级划分树形结构,然后查询数据库的时候会一层一层的嵌套查询。如果层次比较浅这种做法是可取的(或者我们本来就不打算一次将树加载完全,而是在需要时再加载,那分层级的多次加载也许有用武之地)。但是考虑这种情况:我们的树比较深,而且要一次加载完全。要是按照一层一层的加载原则,那么光是访问数据库的查询语句就是指数形式的了。性能肯定不好。那么除了一层一层的查询好有更好的办法吗?肯定是有的,多查询一些资料会发现这种做法比较常见了:(id,pid),通俗说就是一个节点只需要记住自己的id和父亲的id(根节点没有pid可以设置一个特殊值)就可以拥有呈现这棵树的完整结构全部信息了,仔细想一想自己学过的数据结构,是不是这样的?好了这样一来我们在设计数据库的时候就可以很轻松的设计一棵树的树形结构了。那么有个问题,我们在展现出来的时候总不能直接显示一连串的(id,pid)集合吧。我们要的是树形结构。这时候我们其实非常想实现的是从(id,pid)到
(id,children【】)的转化。毕竟我们在展现树形结构的时候后一种格式更适合页面的呈现,而前一种比较适合数据的存储格式。
好了废话不多说了,下面是代码示例:
首先是自定义节点类:
/**
* 节点类
* @author bearsmall
*
*/
public class TreeNode {
private int id;//主键ID
private int pid;//父节点ID
private Object content;//节点内容
private List<TreeNode> children = new ArrayList<TreeNode>();//子孙节点
public TreeNode(int id, Object content) {
this.id = id;
this.content = content;
}
public TreeNode(int id, int pid, Object content) {
this.id = id;
this.pid = pid;
this.content = content;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getPid() {
return pid;
}
public void setPid(int pid) {
this.pid = pid;
}
public Object getContent() {
return content;
}
public void setContent(Object content) {
this.content = content;
}
public List<TreeNode> getChildren() {
return children;
}
public void setChildren(List<TreeNode> children) {
this.children = children;
}
@Override
public String toString() {
return "TreeNode [id=" + id + ", pid=" + pid + ", content=" + content
+ ", children=" + children + "]";
}
}
然后是树节点管理类:
/**
* 树节点管理类
*
* @author bearsmall
*
*/
public class TreeNodeManager {
private List<TreeNode> list;// 树的所有节点
public TreeNodeManager(TreeNode[] items) {
list = new ArrayList<TreeNode>();
for (TreeNode treeNode : items) {
list.add(treeNode);
}
}
public TreeNodeManager(List<TreeNode> items) {
list = items;
}
/**
* 根据节点ID获取一个节点
*
* @param id
* 节点ID
* @return 对应的节点对象
*/
public TreeNode getTreeNodeAT(int id) {
for (TreeNode treeNode : list) {
if (treeNode.getId() == id)
return treeNode;
}
return null;
}
/**
* 获取树的根节点
*
* @return 一棵树的根节点
*/
public TreeNode getRoot() {
for (TreeNode treeNode : list) {
if (treeNode.getPid() == 0)
return treeNode;
}
return null;
}
}
最后是树节点转化类:
/**
* 节点归并类
* @author bearsmall
*
*/
public class TreeNodeMerger {
/**
* 将节点数组归并为一棵树(填充节点的children域)
* 时间复杂度为O(n^2)
* @param items 节点域
* @return
*/
public static TreeNode merge(TreeNode[] items){
TreeNodeManager treeNodeManager = new TreeNodeManager(items);
for (TreeNode treeNode : items) {
if(treeNode.getPid()!=0){
TreeNode t = treeNodeManager.getTreeNodeAT(treeNode.getPid());
t.getChildren().add(treeNode);
}
}
return treeNodeManager.getRoot();
}
/**
* 将节点数组归并为一棵树(填充节点的children域)
* 时间复杂度为O(n^2)
* @param items 节点域
* @return
*/
public static TreeNode merge(List<TreeNode> items){
TreeNodeManager treeNodeManager = new TreeNodeManager(items);
for (TreeNode treeNode : items) {
if(treeNode.getPid()!=0){
TreeNode t = treeNodeManager.getTreeNodeAT(treeNode.getPid());
t.getChildren().add(treeNode);
}
}
return treeNodeManager.getRoot();
}
}
简单测试一下:
public class Main {
public static void main(String[] args) {
TreeNode[] treeNodes = new TreeNode[10];
treeNodes[0] = new TreeNode(1, 0, "");
treeNodes[1] = new TreeNode(2, 1, "");
treeNodes[2] = new TreeNode(3, 1, "");
treeNodes[3] = new TreeNode(4, 2, "");
treeNodes[4] = new TreeNode(5, 3, "");
treeNodes[5] = new TreeNode(6, 4, "");
treeNodes[6] = new TreeNode(7, 3, "");
treeNodes[7] = new TreeNode(8, 5, "");
treeNodes[8] = new TreeNode(9, 6, "");
treeNodes[9] = new TreeNode(10, 9, "");
TreeNode treeNode = TreeNodeMerger.merge(treeNodes);
JSONArray jsonArray = JSONArray.fromObject(treeNode);
System.out.println(jsonArray);
}
}
输出结果:
[{
"children" : [{
"children" : [{
"children" : [{
"children" : [{
"children" : [{
"children" : [],
"pid" : 9,
"id" : 10,
"content" : ""
}
],
"pid" : 6,
"id" : 9,
"content" : ""
}
],
"pid" : 4,
"id" : 6,
"content" : ""
}
],
"pid" : 2,
"id" : 4,
"content" : ""
}
],
"pid" : 1,
"id" : 2,
"content" : ""
}, {
"children" : [{
"children" : [{
"children" : [],
"pid" : 5,
"id" : 8,
"content" : ""
}
],
"pid" : 3,
"id" : 5,
"content" : ""
}, {
"children" : [],
"pid" : 3,
"id" : 7,
"content" : ""
}
],
"pid" : 1,
"id" : 3,
"content" : ""
}
],
"pid" : 0,
"id" : 1,
"content" : ""
}
]
这种格式是不是更清晰呢?
森林管理类:
/**
* 森林节点管理类
*
* @author bearsmall
*
*/
public class ForestNodeManager {
private List<TreeNode> list;// 森林的所有节点
public ForestNodeManager(TreeNode[] items) {
list = new ArrayList<TreeNode>();
for (TreeNode treeNode : items) {
list.add(treeNode);
}
}
public ForestNodeManager(List<TreeNode> items) {
list = items;
}
/**
* 根据节点ID获取一个节点
*
* @param id
* 节点ID
* @return 对应的节点对象
*/
public TreeNode getTreeNodeAT(int id) {
for (TreeNode treeNode : list) {
if (treeNode.getId() == id)
return treeNode;
}
return null;
}
/**
* 获取树的根节点【一个森林对应多颗树】
*
* @return 树的根节点集合
*/
public List<TreeNode> getRoot() {
List<TreeNode> roots = new ArrayList<TreeNode>();
for (TreeNode treeNode : list) {
if (treeNode.getPid() == 0)
roots.add(treeNode);
}
return roots;
}
}
森林节点归并类:
/**
* 节点归并类
* @author bearsmall
*
*/
public class ForestNodeMerger {
/**
* 将节点数组归并为一个森林(多棵树)(填充节点的children域)
* 时间复杂度为O(n^2)
* @param items 节点域
* @return 多棵树的根节点集合
*/
public static List<TreeNode> merge(TreeNode[] items){
ForestNodeManager forestNodeManager = new ForestNodeManager(items);
for (TreeNode treeNode : items) {
if(treeNode.getPid()!=0){
TreeNode t = forestNodeManager.getTreeNodeAT(treeNode.getPid());
t.getChildren().add(treeNode);
}
}
return forestNodeManager.getRoot();
}
/**
* 将节点数组归并为一个森林(多棵树)(填充节点的children域)
* 时间复杂度为O(n^2)
* @param items 节点域
* @return 多棵树的根节点集合
*/
public static List<TreeNode> merge(List<TreeNode> items){
ForestNodeManager forestNodeManager = new ForestNodeManager(items);
for (TreeNode treeNode : items) {
if(treeNode.getPid()!=0){
TreeNode t = forestNodeManager.getTreeNodeAT(treeNode.getPid());
t.getChildren().add(treeNode);
}
}
return forestNodeManager.getRoot();
}
}
测一下:
public class Main2 {
public static void main(String[] args) {
TreeNode[] treeNodes = new TreeNode[10];
treeNodes[0] = new TreeNode(1, 0, "");
treeNodes[1] = new TreeNode(2, 0, "");
treeNodes[2] = new TreeNode(3, 1, "");
treeNodes[3] = new TreeNode(4, 2, "");
treeNodes[4] = new TreeNode(5, 3, "");
treeNodes[5] = new TreeNode(6, 4, "");
treeNodes[6] = new TreeNode(7, 3, "");
treeNodes[7] = new TreeNode(8, 5, "");
treeNodes[8] = new TreeNode(9, 6, "");
treeNodes[9] = new TreeNode(10, 9, "");
List<TreeNode> tns = ForestNodeMerger.merge(treeNodes);
JSONArray jsonArray = JSONArray.fromObject(tns);
System.out.println(jsonArray);
}
}
打印输出:
[{
"children" : [{
"children" : [{
"children" : [{
"children" : [],
"pid" : 5,
"id" : 8,
"content" : ""
}
],
"pid" : 3,
"id" : 5,
"content" : ""
}, {
"children" : [],
"pid" : 3,
"id" : 7,
"content" : ""
}
],
"pid" : 1,
"id" : 3,
"content" : ""
}
],
"pid" : 0,
"id" : 1,
"content" : ""
}, {
"children" : [{
"children" : [{
"children" : [{
"children" : [{
"children" : [],
"pid" : 9,
"id" : 10,
"content" : ""
}
],
"pid" : 6,
"id" : 9,
"content" : ""
}
],
"pid" : 4,
"id" : 6,
"content" : ""
}
],
"pid" : 2,
"id" : 4,
"content" : ""
}
],
"pid" : 0,
"id" : 2,
"content" : ""
}
]
来源:https://blog.csdn.net/u014424628/article/details/51765394/
![](/images/zang.png)
![](/images/jiucuo.png)
猜你喜欢
Spring Security整合CAS的示例代码
Java实现迅雷地址转成普通地址实例代码
mybatis使用Integer类型查询可能出现的问题
C#怎样才能将XML文件导入SQL Server
Android 8.0如何完美适配全局dialog悬浮窗弹出
![](https://img.aspxhome.com/file/2023/8/90138_0s.png)
Java如何在沙箱环境中测试支付宝支付接口
![](https://img.aspxhome.com/file/2023/5/58745_0s.png)
Java synchronized重量级锁实现过程浅析
![](https://img.aspxhome.com/file/2023/7/79187_0s.png)
面试官:java ThreadLocal真的会造成内存泄露吗
![](https://img.aspxhome.com/file/2023/7/79937_0s.png)
Java中SpringSecurity密码错误5次锁定用户的实现方法
JavaWeb中的常用的请求传参注解说明
![](https://img.aspxhome.com/file/2023/1/76201_0s.png)
C# 解析XML和反序列化的示例
Groovy的规则脚本引擎实例解读
![](https://img.aspxhome.com/file/2023/6/65186_0s.jpg)
如何使用Spring自定义Xml标签
![](https://img.aspxhome.com/file/2023/9/75709_0s.jpg)
Maven学习----Maven安装与环境变量配置教程
![](https://img.aspxhome.com/file/2023/8/60678_0s.png)
mybatis-plus QueryWrapper 添加limit方式
SpringBoot创建maven多模块项目实战代码
![](https://img.aspxhome.com/file/2023/1/59391_0s.png)
关于Jsoup将相对路径转为绝对路径的方法
![](https://img.aspxhome.com/file/2023/4/63844_0s.png)
JavaWeb实现多文件上传及zip打包下载
c#使用linq把多列的List转化为只有指定列的List
![](https://img.aspxhome.com/file/2023/2/82112_0s.png)
Android开发仿映客送礼物效果
![](https://img.aspxhome.com/file/2023/3/93293_0s.gif)