2026/4/17 17:25:31
网站建设
项目流程
网站微信分享怎么做,php网站开发思路,最简单的网站模板下载,网站开发的形式有多种方式视频看了几百小时还迷糊#xff1f;关注我#xff0c;几分钟让你秒懂#xff01;#x1f9e9; 一、需求场景#xff1a;为什么需要树形结构#xff1f;在实际开发中#xff0c;树形结构无处不在#xff1a;组织架构#xff1a;公司 → 部门 → 小组 → 员工#xff1…视频看了几百小时还迷糊关注我几分钟让你秒懂 一、需求场景为什么需要树形结构在实际开发中树形结构无处不在组织架构公司 → 部门 → 小组 → 员工菜单权限系统管理 → 用户管理 → 新增/编辑商品分类电子产品 → 手机 → 智能手机 → 国产评论回复主评论 → 子评论 → 孙评论。但数据库通常用“平铺表”存储id,parent_id,name如何高效转成树✅ 目标一行代码将 List 转为 Tree️ 二、通用树节点接口设计先定义一个通用接口让所有树节点实现它import java.util.List; public interface TreeNodeT { String getId(); String getParentId(); void setChildren(ListT children); } 使用泛型T支持任意实体类Menu、Dept、Category 等。 三、示例实体类以菜单为例import lombok.Data; import java.util.ArrayList; import java.util.List; Data public class Menu implements TreeNodeMenu { private String id; private String parentId; private String name; private Integer sort; private ListMenu children new ArrayList(); Override public String getId() { return this.id; } Override public String getParentId() { return this.parentId; } Override public void setChildren(ListMenu children) { this.children children; } } 注意children字段必须存在并提供 setter。 四、核心工具类TreeBuilder重点import java.util.*; import java.util.stream.Collectors; public class TreeBuilder { /** * 将平铺列表构建成树形结构 * * param nodes 所有节点平铺 * param rootParentId 根节点的 parentId如 0 或 null * param T 节点类型 * return 树形列表 */ public static T extends TreeNodeT ListT buildTree(ListT nodes, String rootParentId) { if (nodes null || nodes.isEmpty()) { return Collections.emptyList(); } // 1. 创建 id - node 的映射提升查找效率 O(1) MapString, T nodeMap nodes.stream() .collect(Collectors.toMap(TreeNode::getId, node - node)); // 2. 初始化 children 列表 MapString, ListT childrenMap new HashMap(); for (T node : nodes) { childrenMap.put(node.getId(), new ArrayList()); } // 3. 遍历所有节点构建父子关系 ListT roots new ArrayList(); for (T node : nodes) { String parentId node.getParentId(); if (Objects.equals(parentId, rootParentId)) { // 是根节点 roots.add(node); } else { // 找到父节点添加到其 children T parent nodeMap.get(parentId); if (parent ! null) { childrenMap.get(parentId).add(node); } // 如果父节点不存在可选择忽略或抛异常 } } // 4. 设置每个节点的 children for (Map.EntryString, ListT entry : childrenMap.entrySet()) { String nodeId entry.getKey(); T node nodeMap.get(nodeId); if (node ! null) { node.setChildren(entry.getValue()); } } return roots; } }✅ 时间复杂度O(n)远优于递归O(n²) 五、使用示例1. 模拟数据库数据public class TreeDemo { public static void main(String[] args) { ListMenu menus Arrays.asList( new Menu(1, 0, 系统管理, 1), new Menu(2, 0, 内容管理, 2), new Menu(3, 1, 用户管理, 1), new Menu(4, 1, 角色管理, 2), new Menu(5, 3, 新增用户, 1), new Menu(6, 3, 编辑用户, 2), new Menu(7, 2, 文章管理, 1) ); // 构建树 ListMenu tree TreeBuilder.buildTree(menus, 0); // 打印结果可用 Jackson 格式化 System.out.println(tree); } }2. 输出效果结构化[ { id: 1, parentId: 0, name: 系统管理, children: [ { id: 3, parentId: 1, name: 用户管理, children: [ {id: 5, parentId: 3, name: 新增用户, children: []}, {id: 6, parentId: 3, name: 编辑用户, children: []} ] }, { id: 4, parentId: 1, name: 角色管理, children: [] } ] }, { id: 2, parentId: 0, name: 内容管理, children: [ {id: 7, parentId: 2, name: 文章管理, children: []} ] } ]✅ 完美支持无限层级❌ 六、反例 常见错误反例 1用递归构建树性能差// ❌ 每找一个子节点都要遍历整个 listn 层树 → O(n²) public ListMenu buildByRecursion(String parentId, ListMenu all) { return all.stream() .filter(m - Objects.equals(m.getParentId(), parentId)) .peek(m - m.setChildren(buildByRecursion(m.getId(), all))) .collect(Collectors.toList()); } 数据量大时如 1000 节点响应慢到超时反例 2不处理“父节点不存在”的情况数据库里有个节点parentId 999但id999的记录被删了如果不处理可能 NPE 或数据丢失。✅ 建议日志告警“孤立节点idxxx”或自动挂到根节点下根据业务决定。反例 3硬编码实体类无法复用// ❌ 只能处理 Menu不能处理 Dept、Category public class MenuTreeBuilder { ... }✅ 正确用泛型 接口一套代码通吃所有树⚠️ 七、增强建议生产级需求实现方式排序在buildTree后对children调用sort()过滤支持传入PredicateT过滤节点路径递归生成path /系统管理/用户管理扁平化提供flattenTree()方法反向操作循环引用检测构建时检查id parentId或环形依赖例如加排序// 在 buildTree 最后加 roots.forEach(TreeBuilder::sortChildren); private static T extends TreeNodeT void sortChildren(T node) { if (node instanceof Comparable) { node.getChildren().sort(null); } node.getChildren().forEach(TreeBuilder::sortChildren); } 八、总结特性说明通用性任何实现TreeNode的类都能用高性能O(n) 时间复杂度Map 索引加速安全处理孤立节点、空值等边界情况易用一行代码TreeBuilder.buildTree(list, 0)从此告别手写递归轻松搞定组织架构、菜单、分类树视频看了几百小时还迷糊关注我几分钟让你秒懂