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/


猜你喜欢
- 前言日常编码过程中,最重要的技能不是说你学会使用很多最新的编程技术或者做出一个高大上的系统。而是你在写代码过程中,对异常的处理,是否系统可以
- package com.qhdstar.java.pdf;import java.awt.Color;import java.io.File
- 最近有一个项目要用到年份周期,用于数据统计图表展示使用,当中用到年份周期,以及年份周期所在的日期范围。当初设想通过已知数据来换算年份周期,经
- 定义可理解为 适配广泛的类型,即参数化类型,可以把类型像方法的参数那样进行传递。// 以ArrayList为示例// 泛型T可以是任意类pu
- 本文实例为大家分享了Unity Shader实现模糊效果的具体代码,供大家参考,具体内容如下今天分享一个超简单实现模糊效果的方法,先上图:核
- 需求说明要求根据用户输入,生成相应组数的电话号码实现思路1、通过百度,获取对应真实世界中电话号码的头三位数2、采用Math.random()
- BASE64 编码是一种常用的字符编码,在很多地方都会用到。但base64不是安全领域下的加密解密算法。能起到安全作用的效果很差,而且很容易
- java就业前需要掌握的专业技能1.熟练的使用Java语言进行面向对象程序设计,有良好的编程习惯,熟悉常用的Java API,包括集合框架、
- 这里我记录一个比较简单方便操作的JAVA上传文件图片到服务器并且保存,具体内容如下首先是页面html的 我这是提交一
- 实现Back键功能方法有:一:重写onBackPressed方法@Override public void onBackPress
- 文件写入为提供相对较高性能的文件读写操作,这里果断选择了 NIO 对文件的操作,因为业务背景需要数据的安全落盘。这里主要采用 ByteBuf
- 在使用springMVC框架构建web应用,客户端常会请求字符串、整型、json等格式的数据,通常使用@ResponseBody注解使 co
- 实现过滤器和 * 首先,我们先来看一下二者在 Spring Boot 项目中的具体实现,这对后续理解二者的区别有很大的帮助。a) 实现过滤器
- 项目中需要用到类似公告栏的控件,能用的基本不支持多行显示,于是只好自己动手,苦于没有自定义过一个像样的控件,借鉴Android公告条demo
- 一、概述 这一章先来点有意思的百度地图应用示例,然后再分章详细介绍用C#开发Android App的各种基本技术。 本章
- mybatis-plus Condition拼接Sql语句各方法1.setSqlSelect—用于添加查询的列信息public Wrappe
- 在Flutter中实现整个App变为灰色是非常简单的,只需要在最外层的控件上包裹ColorFiltered,用法如下:@overrideWi
- 背景我们在多模块项目开发过程中,会遇到这样的场景,工程里依赖了一个自己的或者其他同事的 aar 模块,有时候为了开发调试方便,经常会把 aa
- 微信小程序 navigator 跳转url传递参数使用方法说明(1)传值:在navigator的属性url后拼接?id(参数名字
- 寻找到application.yml的读取的操作。从spring.factories 中查看到# Application Listeners