JAVA将List转成Tree树形结构数据和深度优先遍历
引言:
在日常开发中,我们经常会遇到需要将数据库中返回的数据转成树形结构的数据返回,或者需要对转为树结构后的数据绑定层级关系再返回,比如需要统计当前节点下有多少个节点等,因此我们需要封装一个ListToTree的工具类和学会如何通过深度优先遍历数据。
数据准备:
先简单准备一下具有父子关系的数据。
package data;public class OrgData {private String id;private String pId;private String orgName;public String getId() {return id;}public void setId(String id) {this.id = id;}public String getpId() {return pId;}public void setpId(String pId) {this.pId = pId;}public String getOrgName() {return orgName;}public void setOrgName(String orgName) {this.orgName = orgName;}
}
package data;import java.util.ArrayList;
import java.util.List;public class SingData {public static List<OrgData> getData() {OrgData orgData1 = new OrgData();orgData1.setId("1");orgData1.setpId("root");orgData1.setOrgName("根节点A");OrgData orgData2 = new OrgData();orgData2.setId("2");orgData2.setpId("root");orgData2.setOrgName("根节点B");OrgData orgData3 = new OrgData();orgData3.setId("3");orgData3.setpId("1");orgData3.setOrgName("A目录");OrgData orgData4 = new OrgData();orgData4.setId("4");orgData4.setpId("2");orgData4.setOrgName("B目录");List<OrgData> list = new ArrayList<>();list.add(orgData1);list.add(orgData2);list.add(orgData3);list.add(orgData4);return list;}
}
正常情况下,我们都会选择封装一个将List转换为Tree的工具类,并且通过链式顺序LinkedList存储来遍历Tree数据,这里使用stream来实现,如下:
package data;import java.util.List;public class TreeBean {private String treeId;private String treePid;private String orgName;private Integer flag = 0;private List<TreeBean> children;private OrgData orgData;public String getTreeId() {return treeId;}public void setTreeId(String treeId) {this.treeId = treeId;}public String getOrgName() {return orgName;}public void setOrgName(String orgName) {this.orgName = orgName;}public String getTreePid() {return treePid;}public void setTreePid(String treePid) {this.treePid = treePid;}public List<TreeBean> getChildren() {return children;}public void setChildren(List<TreeBean> children) {this.children = children;}public OrgData getOrgData() {return orgData;}public void setOrgData(OrgData orgData) {this.orgData = orgData;}public Integer getFlag() {return flag;}public void setFlag(Integer flag) {this.flag = flag;}@Overridepublic String toString() {return "TreeBean{" +"treeId='" + treeId + '\'' +", treePid='" + treePid + '\'' +", orgName='" + orgName + '\'' +", children=" + children +'}';}
}
执行结果:
620fc2d13f944d61888c2f0af8198ad2.png
对tree数据进行遍历,通过链表的形式:
import data.OrgData;
import data.SingData;
import data.TreeBean;
import utils.ListToTreeUtil;import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;public class Main {public static void main(String[] args) {// 模拟查询数据List<OrgData> orgDataList = SingData.getData();// 构建tree数据List<TreeBean> treeBean = ListToTreeUtil.toTree(orgDataList, "root");// 使用LinkedList实现链式队列,实现深度遍历LinkedList<TreeBean> stack = new LinkedList<>();stack.addAll(treeBean);while (!stack.isEmpty()) {// 从栈顶开始访问TreeBean pop = stack.peek();// Flag=1表示已经遍历过一次且该节点存在子节点if (pop.getFlag() == 1) {OrgData orgData =pop.getOrgData();List<TreeBean> children = pop.getChildren();// 获取子节点的节点名称,也可以进行其他的操作List<String> collect = children.stream().map(TreeBean::getOrgName).collect(Collectors.toList());StringBuilder builder = new StringBuilder();for (String s : collect) {builder.append(s);builder.append(">");}pop.setOrgName(builder.toString());orgData.setOrgName(pop.getOrgName());// pop出栈,当前节点已经统计完,出栈获取下一个栈顶peekstack.pop();} else {// flag为0表示未遍历,判断是否已经遍历到叶子节点(最底部)if (pop.getChildren()!= null && !pop.getChildren().isEmpty()) {// 非叶子节点pop.setFlag(1);List<TreeBean> children = pop.getChildren();for (TreeBean child : children) {// 将叶子节点入栈,放到栈顶,实现深度遍历,nextstack.push(child);}} else {// 叶子节点直接出栈即可,cnt为本身stack.pop();}}}// 遍历最终的数据for (OrgData orgData : orgDataList) {System.out.println(orgData.toString());}}
}
但是现在有一个问题,当我们响应的数据从OrgData换到其他类型的时候,这时候就需要封装成一个泛型类使得我们的tree数据生成类变成一个通用的,完整代码如下:
完整代码:JAVA将List转为Tree和深度优先遍历
package data;import java.util.List;public interface Tree<T> {String getTreeId();String getTreePid();void setChild(List<T> list);
}
package data;import java.util.List;/*** 实现Tree<OrgData>并定义响应类型为本身* 定义转为树的参数返回
*/
public class OrgData implements Tree<OrgData>{private String id;private String pId;private String orgName;// 转成树需要的参数private Integer flag = 0;private List<OrgData> child;public String getId() {return id;}public void setId(String id) {this.id = id;}public String getpId() {return pId;}public void setpId(String pId) {this.pId = pId;}public String getOrgName() {return orgName;}public void setOrgName(String orgName) {this.orgName = orgName;}public Integer getFlag() {return flag;}public void setFlag(Integer flag) {this.flag = flag;}public List<OrgData> getChild() {return child;}@Overridepublic String toString() {return "OrgData{" +"id='" + id + '\'' +", pId='" + pId + '\'' +", orgName='" + orgName + '\'' +'}';}@Overridepublic String getTreeId() {return id;}@Overridepublic String getTreePid() {return pId;}@Overridepublic void setChild(List<OrgData> list) {this.child = list;}
}
ListToTree方法
package utils;import data.OrgData;
import data.SingData;
import data.Tree;
import data.TreeBean;import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;/*** 将List转为Tree* <T extends Tree>告诉编译器有Tree的get方法**/
public class ListToTreeUtil {public static <T extends Tree> List<T> toTree(List<T> list, String root) {// 当根节点为null时,定义一个初始值,防止nullString treeRoot = "treeRoot";String finalRoot = root;if (list.isEmpty()) {return new ArrayList<>();}// 构建Map数据// 根据pid分组,获取所有的子节点集合Map<String, List<T>> childMap =list.stream().collect(Collectors.groupingBy(item -> {String treePid = item.getTreePid();if (treePid == null) {treePid = treeRoot;}return treePid;}));return list.stream().peek(data -> {List<T> children = childMap.get(data.getTreeId());if (children != null && !children.isEmpty()) {data.setChild(children);}}).filter(data -> data.getTreePid().equals(finalRoot)).collect(Collectors.toList());}
}
深度优先遍历
import data.OrgData;
import data.SingData;
import data.TreeBean;
import utils.ListToTreeUtil;import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;public class Main {public static void main(String[] args) {// 模拟查询数据List<OrgData> orgDataList = SingData.getData();// 构建tree数据List<OrgData> treeBean = ListToTreeUtil.toTree(orgDataList, "root");// 使用LinkedList实现链式队列,实现深度遍历LinkedList<OrgData> stack = new LinkedList<>();stack.addAll(treeBean);while (!stack.isEmpty()) {// 从栈顶开始访问OrgData pop = stack.peek();// Flag=1表示已经遍历过一次且该节点存在子节点if (pop.getFlag() == 1) {List<OrgData> children = pop.getChild();// 获取子节点的节点名称,也可以进行其他的操作List<String> collect = children.stream().map(OrgData::getOrgName).collect(Collectors.toList());StringBuilder builder = new StringBuilder();for (String s : collect) {builder.append(s);builder.append(">");}pop.setOrgName(builder.toString());// pop出栈,当前节点已经统计完,出栈获取下一个栈顶peekstack.pop();} else {// flag为0表示未遍历,判断是否已经遍历到叶子节点(最底部)if (pop.getChild()!= null && !pop.getChild().isEmpty()) {// 非叶子节点pop.setFlag(1);List<OrgData> children = pop.getChild();for (OrgData child : children) {// 将叶子节点入栈,放到栈顶,实现深度遍历,nextstack.push(child);}} else {// 叶子节点直接出栈即可,cnt为本身stack.pop();}}}// 遍历最终的数据for (OrgData orgData : orgDataList) {System.out.println(orgData.toString());}}
}
相关文章:
JAVA将List转成Tree树形结构数据和深度优先遍历
引言: 在日常开发中,我们经常会遇到需要将数据库中返回的数据转成树形结构的数据返回,或者需要对转为树结构后的数据绑定层级关系再返回,比如需要统计当前节点下有多少个节点等,因此我们需要封装一个ListToTree的工具类…...
设计模式——开闭、单一职责及里氏替换原则
设计原则是指导软件设计和开发的一系列原则,它们帮助开发者创建出易于维护、扩展和理解的代码。以下是你提到的几个关键设计原则的简要说明: 开闭原则(Open/Closed Principle, OCP): 开闭原则由Bertrand Meyer提出&am…...
代码随想录算法训练营第59天:动态[1]
代码随想录算法训练营第59天:动态 两个字符串的删除操作 力扣题目链接(opens new window) 给定两个单词 word1 和 word2,找到使得 word1 和 word2 相同所需的最小步数,每步可以删除任意一个字符串中的一个字符。 示例: 输入: …...
jvm性能监控常用工具
在java的/bin目录下有许多java自带的工具。 我们常用的有 基础工具 jar:创建和管理jar文件 java:java运行工具,用于运行class文件或jar文件 javac:java的编译器 javadoc:java的API文档生成工具 性能监控和故障处理 jps jstat…...
ISP IC/FPGA设计-第一部分-SC130GS摄像头分析-IIC通信(1)
1.摄像头模组 SC130GS通过一个引脚(SPI_I2C_MODE)选择使用IIC或SPI配置接口,通过查看摄像头模组的原理图,可知是使用IIC接口; 通过手册可知IIC设备地址通过一个引脚控制,查看摄像头模组的原理图ÿ…...
HTTP协议头中X-Forwarded-For是能做什么?
X-Forwarded-For和相关几个头部的理解 $remote_addr 是nginx与客户端进行TCP连接过程中,获得的客户端真实地址. Remote Address 无法伪造,因为建立 TCP 连接需要三次握手,如果伪造了源 IP,无法建立 TCP 连接,更不会有后…...
Linux高并发服务器开发(八)Socket和TCP
文章目录 1 IPV4套接字结构体2 TCP客户端函数 3 TCP服务器流程函数代码粘包 4 三次握手5 四次挥手6 滑动窗口 1 IPV4套接字结构体 2 TCP客户端 特点:出错重传 每次发送数据对方都会回ACK,可靠 tcp是打电话的模型,建立连接 使用连接 关闭连接…...
力扣第220题“存在重复元素 III”
在本篇文章中,我们将详细解读力扣第220题“存在重复元素 III”。通过学习本篇文章,读者将掌握如何使用桶排序和滑动窗口来解决这一问题,并了解相关的复杂度分析和模拟面试问答。每种方法都将配以详细的解释,以便于理解。 问题描述…...
Qt实战项目——贪吃蛇
一、项目介绍 本项目是一个使用Qt框架开发的经典贪吃蛇游戏,旨在通过简单易懂的游戏机制和精美的用户界面,为玩家提供娱乐和编程学习的机会。 游戏展示 二、主要功能 2.1 游戏界面 游戏主要是由三个界面构成,分别是游戏大厅、难度选择和游戏…...
Windows 10,11 Server 2022 Install Docker-Desktop
docker 前言 Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 Linux或Windows 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口。 docker-compose Compose 是用于定义和运行…...
C++中的RAII(资源获取即初始化)原则
C中的RAII(Resource Acquisition Is Initialization,资源获取即初始化)原则是一种管理资源、避免资源泄漏的惯用法。RAII是C之父Bjarne Stroustrup提出的设计理念,其核心思想是将资源的获取(如动态内存分配、文件句柄、…...
【机器学习】Whisper:开源语音转文本(speech-to-text)大模型实战
目录 一、引言 二、Whisper 模型原理 2.1 模型架构 2.2 语音处理 2.3 文本处理 三、Whisper 模型实战 3.1 环境安装 3.2 模型下载 3.3 模型推理 3.4 完整代码 3.5 模型部署 四、总结 一、引言 上一篇对ChatTTS文本转语音模型原理和实战进行了讲解&a…...
ubuntu22.04 编译安装openssl C++ library
#--------------------------------------------------------------------------- # openssl C library # https://www.openssl.org/source/index.html #--------------------------------------------------------------------------- cd /opt/download # 下载openssl-3.0.13…...
百度Agent初体验(制作步骤+感想)
现在AI Agent很火,最近注册了一个百度Agent体验了一下,并做了个小实验,拿它和零一万物(Yi Large)和文心一言(ERNIE-4.0-8K-latest)阅读了相同的一篇网页资讯,输出资讯摘要࿰…...
7-491 3名同学5门课程成绩,输出最好成绩及所在的行和列(二维数组作为函数的参数)
编程:数组存储3名同学5门课程成绩 输出最好成绩及所在的行和列 要求:将输入、查找和打印的功能编写成函数 并将二维数组通过指针参数传递的方式由主函数传递到子函数中 输入格式: 每行输入一个同学的5门课的成绩,每个成绩之间空一格,见输入…...
OpenCloudOS开源的操作系统
OpenCloudOS 是一款开源的操作系统,致力于提供高性能、稳定和安全的操作系统环境,以满足现代计算和应用程序的需求。它结合了现代操作系统设计的最新技术和实践,为开发者和企业提供了一个强大的平台。本文将详细介绍 OpenCloudOS 的背景、特性…...
排序题目:多数元素 II
文章目录 题目标题和出处难度题目描述要求示例数据范围进阶 前言解法一思路和算法代码复杂度分析 解法二思路和算法代码复杂度分析 解法三思路和算法代码复杂度分析 题目 标题和出处 标题:多数元素 II 出处:229. 多数元素 II 难度 3 级 题目描述 …...
<电力行业> - 《第1课:电力行业的五大四小》
1 什么是电力行业的五大四小? 我们常说的电力行业的五大四小,指的是电力行业有实力的公司,分为:较强梯队的五大集团、较弱梯队的四小豪门。 五个实力雄厚的集团,分别是: 中国华能集团公司中国大唐集团公…...
数据库定义语言(DDL)
数据库定义语言(DDL) 一、数据库操作 1、 查询所有的数据库 SHOW DATABASES;效果截图: 2、使用指定的数据库 use 2403 2403javaee;效果截图: 3、创建数据库 CREATE DATABASE 2404javaee;效果截图: 4、删除数据…...
mybatis实现多表查询
mybatis高级查询【掌握】 1、准备工作 【1】包结构 创建java项目,导入jar包和log4j日志配置文件以及连接数据库的配置文件; 【2】导入SQL脚本 运行资料中的sql脚本:mybatis.sql 【3】创建实体来包,导入资料中的pojo 【4】User…...
极简黑魔法:用 gh gist 搭建我们的私有配置分发 CDN
在多端协作的时代,我们经常需要在 PC、手机和路由器之间同步一些私密的订阅配置(如应用服务配置文件,凭据等)。 如果使用公共 Gist 会有隐私泄露风险;维护一个私有 Git 仓库又需要处理复杂的 API Token 鉴权࿰…...
OpenClaw 落地企业微信:AI 驱动办公,效率提升看得见
前言 在企业数字化办公场景下,将智能对话功能与企业微信集成可有效提升内部沟通效率和业务响应速度。本文系统阐述了OpenClaw与企业微信的对接方案,该方案采用可视化操作界面实现智能机器人的快速部署,助力企业便捷构建专属AI助手࿰…...
不只是大小端:用Python脚本自动解析DBC文件中的Motorola和Intel信号
自动化解析DBC信号:Python实战Motorola与Intel字节顺序处理 在汽车电子和工业控制领域,CAN总线通信扮演着至关重要的角色。DBC文件作为描述CAN通信协议的标准化格式,包含了消息、信号以及各种通信参数的完整定义。对于测试工程师和嵌入式开发…...
如何永久保存微信聊天记录?终极指南:从导出到年度报告完整流程
如何永久保存微信聊天记录?终极指南:从导出到年度报告完整流程 【免费下载链接】WeChatMsg 提取微信聊天记录,将其导出成HTML、Word、CSV文档永久保存,对聊天记录进行分析生成年度聊天报告 项目地址: https://gitcode.com/GitHu…...
别再用docker tag了!深入理解Containerd生态:crictl、ctr与nerdctl到底该怎么选?
深入解析Containerd生态:crictl、ctr与nerdctl的镜像管理实战指南 在容器技术快速发展的今天,越来越多的开发者正从Docker生态转向Containerd这一更轻量、更符合Kubernetes标准的运行时环境。但当我们真正开始使用Containerd时,往往会遇到一个…...
微软MOS认证-Word专家级|超全报考指南
不管是大学生还是职场人,Word 都是绕不开的工具。但多数人只会基础打字排版,面对长文档、规范报告时常常手忙脚乱。MOSWord 专家级认证,正是帮你把 “普通 Word” 变成 “高-效办公武器” 的实用路径。#微软mos认证 #大学生考证 #mos认证考试…...
从零构建MCP服务:AI应用外部工具集成入门指南
1. 项目概述:从零构建你的第一个MCP服务 最近在AI应用开发圈里,MCP(Model Context Protocol)这个词的热度越来越高。如果你正在尝试将大型语言模型(LLM)的能力集成到自己的应用里,或者想为你的A…...
开源工作流引擎ByteChef:从组件化架构到自动化编排实战
1. 项目概述:一个面向开发者的自动化工作流引擎如果你是一名开发者,或者经常需要处理跨系统、跨应用的数据同步、定时任务、API调用编排,那么你大概率对“自动化”有着强烈的需求。我们可能都经历过这样的场景:每天手动从A系统导出…...
别再复制官网代码了!Vue + Ant Design 图标与分隔符的本地化实战(附避坑指南)
Vue Ant Design 图标与分隔符的本地化实战指南 在Vue项目中使用Ant Design Vue组件库时,很多开发者习惯直接从官网复制示例代码。然而,这种"拿来主义"常常导致项目运行时出现图标不显示、样式依赖CDN资源等问题。本文将带你从零开始ÿ…...
Obsidian数据迁移终极指南:如何将10+平台笔记一键导入知识库
Obsidian数据迁移终极指南:如何将10平台笔记一键导入知识库 【免费下载链接】obsidian-importer Obsidian Importer lets you import notes from other apps and file formats into your Obsidian vault. 项目地址: https://gitcode.com/gh_mirrors/ob/obsidian-i…...
