当前位置: 首页 > news >正文

Java构建Tree并实现节点名称模糊查询

乐于学习分享… 大家加油努力

package com.tom.backtrack;import lombok.Data;
import lombok.Getter;import java.util.ArrayList;
import java.util.List;
import java.util.Objects;/*** 树节点** @author zx* @date 2025-05-27 19:51*/
@Data
public class TreeNode {private Long id;private Long parentId;private String name;private List<TreeNode> children;/*** 是否根节点*/@Getterprivate Boolean rootNode;/*** 是否叶子节点**/@Getterprivate Boolean leafNode;/*** 设置子节点数据,设置为protected禁止外部调用**/public void setChildren(List<TreeNode> children) {this.children = children;this.rootNode = Objects.equals(getParentId(), 0L);this.leafNode = children == null || children.isEmpty();}// 模糊搜索方法,返回符合条件的节点列表public List<TreeNode> fuzzySearch(String query) {List<TreeNode> results = new ArrayList<>(); // 存储搜索结果fuzzySearchHelper(this, query, results); // 调用搜索辅助方法return results;}// 判断节点是否有子节点的方法private boolean hasLeaf(TreeNode node) {for (TreeNode child : node.children) {if (child.children.isEmpty()) { // 如果存在叶子节点,返回truereturn true;}}return false; // 否则返回false}// 判断节点的子节点是否存在符合条件的节点的方法private boolean hasMatchingChild(TreeNode node, String query) {for (TreeNode child : node.children) {if (child.name.contains(query) || hasMatchingChild(child, query)) {return true; // 如果子节点的名称包含查询字符串,或者子节点的子节点存在符合条件的节点,则返回true}}return false; // 否则返回false}// 递归搜索辅助方法private void fuzzySearchHelper(TreeNode node, String query, List<TreeNode> results) {// 如果当前节点的值包含查询字符串,并且至少有一个子节点也符合查询条件,则将其添加到结果列表中if (node.name.contains(query) || hasMatchingChild(node, query)) {results.add(node);}// 递归搜索子节点List<TreeNode> removableChildren = new ArrayList<>();for (TreeNode child : node.children) {fuzzySearchHelper(child, query, results);if (!hasLeaf(child)) {removableChildren.add(child);}}// 删除没有树叶的子节点for (TreeNode child : removableChildren) {node.children.remove(child);}}
}
package com.tom.backtrack;import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;/*** <h1>树工具类</h1>* <pre>*  1.该工具类支持: 构建树结构、模糊查询*  2.优化建议:*      1.扁平化处理:如果只需要匹配结果而不需要保持树结构,可以先将所有节点展平为列表再进行过滤*      2.性能优化:*          - 对于大数据量场景,可结合缓存机制或异步加载*          - 使用 equalsIgnoreCase() 支持不区分大小写的模糊匹配*      3.高级模糊匹配:使用正则表达式或第三方库如 Apache Commons Text 的模糊匹配功能*  3.注意事项:*      1.若需返回完整树结构但仅展示匹配路径,可在递归中剪枝保留匹配路径*      2.若数据来源于数据库,推荐在 SQL 层面使用 LIKE '%keyword%' 进行模糊查询以减少内存开销(多次 SQL 查询 + 应用层拼接)**  案例:*  场景假设:*   tree_node 的表,用于存储树形结构数据:*      CREATE TABLE tree_node (*        id BIGINT PRIMARY KEY,*        parent_id BIGINT, -- 父节点ID,顶级节点为0或NULL*        name VARCHAR(255) -- 节点名称*      );*   根据某个关键词模糊查询节点名称,并获取其所有父节点路径或子树结构。*  实现方式一:多次 SQL 查询 + 应用层拼接(推荐)*      步骤:*          - 先模糊查询匹配的节点*          - 递归向上查父节点,直到根节点*          - 应用层构建树结构*      示例代码:*          1.模糊查询匹配节点*              SELECT * FROM tree_node WHERE name LIKE '%keyword%';*          2.根据匹配节点 ID,逐级向上查找父节点*              -- 假设匹配到 id = 5 的节点*              SELECT * FROM tree_node WHERE id = 5;*              SELECT * FROM tree_node WHERE id = (SELECT parent_id FROM tree_node WHERE id = 5);*              -- 依次类推,直到 parent_id 为 NULL 或 0**              通过java、python等代码逻辑循环执行上述语句,构建出完整路径。*  实现方式二:使用存储过程模拟递归查询(适用于固定层级)*      创建一个存储过程,递归查找所有子节点:*          DELIMITER $$**          CREATE PROCEDURE search_tree(IN keyword VARCHAR(255))*          BEGIN*              CREATE TEMPORARY TABLE IF NOT EXISTS temp_result (*                  id BIGINT,*                  parent_id BIGINT,*                  name VARCHAR(255)*              );**              TRUNCATE TABLE temp_result;**              -- 插入初始匹配节点*              INSERT INTO temp_result (id, parent_id, name)*              SELECT id, parent_id, name FROM tree_node WHERE name LIKE CONCAT('%', keyword, '%');**              -- 循环插入父节点*              WHILE ROW_COUNT() > 0 DO*                  INSERT INTO temp_result (id, parent_id, name)*                  SELECT t.id, t.parent_id, t.name*                  FROM tree_node t*                  INNER JOIN temp_result tr ON t.id = tr.parent_id*                  WHERE t.id NOT IN (SELECT id FROM temp_result);*              END WHILE;**              -- 返回结果*              SELECT * FROM temp_result ORDER BY id;**              DROP TEMPORARY TABLE IF EXISTS temp_result;*          END$$**          DELIMITER ;**       调用方式:*          CALL search_tree('1-2-1');*       注意:*          - MySQL 5.7 不支持 CTE,建议优先在应用层处理树结构。*          - 如果可以升级到 MySQL 8.0,可以直接使用递归查询(CTE):*                WITH RECURSIVE cte AS (*                  SELECT * FROM tree_node WHERE name LIKE '%keyword%'*                  UNION ALL*                  SELECT t.* FROM tree_node t INNER JOIN cte c ON t.id = c.parent_id*              )**              SELECT * FROM cte;** </pre>* @author zx* @date 2025-05-27 20:05*/
public class TreeUtil {public static List<TreeNode> buildTree(List<TreeNode> treeNodeList) {if (treeNodeList == null || treeNodeList.size() == 0) {return treeNodeList;}// 2.根据父节点进行分组Map<Long, List<TreeNode>> groups = treeNodeList.stream().collect(Collectors.groupingBy(TreeNode::getParentId));return treeNodeList.stream().filter(Objects::nonNull).peek(pnd -> {List<TreeNode> ts = groups.get(pnd.getId());pnd.setChildren(ts);}).filter(TreeNode::getRootNode).collect(Collectors.toList());}public static List<TreeNode> fuzzySearch(List<TreeNode> treeNodes, String keyword) {List<TreeNode> result = new ArrayList<>();for (TreeNode node : treeNodes) {traverseAndCollect(node, keyword, result);}return result;}private static boolean traverseAndCollect(TreeNode node, String keyword, List<TreeNode> result) {boolean isMatched = false;//模糊查询---这里使用正则表达式,临时使用字符串包含方法if (node.getName().contains(keyword)) {isMatched = true;}if (node.getChildren() != null && !node.getChildren().isEmpty()) {List<TreeNode> matchedChildren = new ArrayList<>();for (TreeNode child : node.getChildren()) {if (traverseAndCollect(child, keyword, result)) {matchedChildren.add(child);isMatched = true;}}// 可选:只保留匹配的子节点node.setChildren(matchedChildren);}if (isMatched) {result.add(node);}return isMatched;}public static List<TreeNode> buildTreeNodeData() {List<TreeNode> treeNodeList = new ArrayList<>();TreeNode treeNode1 = new TreeNode();treeNode1.setId(1L);treeNode1.setParentId(0L);treeNode1.setName("1");treeNodeList.add(treeNode1);TreeNode treeNode2 = new TreeNode();treeNode2.setId(2L);treeNode2.setParentId(0L);treeNode2.setName("2");treeNodeList.add(treeNode2);TreeNode treeNode3 = new TreeNode();treeNode3.setId(3L);treeNode3.setParentId(1L);treeNode3.setName("1-1");treeNodeList.add(treeNode3);TreeNode treeNode4 = new TreeNode();treeNode4.setId(4L);treeNode4.setParentId(1L);treeNode4.setName("1-2");treeNodeList.add(treeNode4);TreeNode treeNode5 = new TreeNode();treeNode5.setId(5L);treeNode5.setParentId(4L);treeNode5.setName("1-2-1");treeNodeList.add(treeNode5);TreeNode treeNode6 = new TreeNode();treeNode6.setId(6L);treeNode6.setParentId(2L);treeNode6.setName("2-1");treeNodeList.add(treeNode6);TreeNode treeNode7 = new TreeNode();treeNode7.setId(7L);treeNode7.setParentId(2L);treeNode7.setName("2-2");treeNodeList.add(treeNode7);TreeNode treeNode8 = new TreeNode();treeNode8.setId(8L);treeNode8.setParentId(6L);treeNode8.setName("2-2-1");treeNodeList.add(treeNode8);return treeNodeList;}public static void main(String[] args) {List<TreeNode> treeNodeList = buildTree(buildTreeNodeData());List<TreeNode> newTreeNodeList = new ArrayList<>();newTreeNodeList.addAll(treeNodeList);System.out.println(newTreeNodeList);String keyword = "1-2-1";List<TreeNode> searchResultTreeNodeList = buildTree(fuzzySearch(treeNodeList, keyword));System.out.println(searchResultTreeNodeList);}
}

相关文章:

  • 商用密码 vs 普通密码:安全加密的核心区别
  • cos和dmz学习
  • WPF【10_2】数据库与WPF实战-示例
  • WEB安全威胁与SSL
  • MQTT over SSL/TLS:工业网关如何构建端到端加密的数据传输通道
  • EMQX启用单向认证的SSl/TLS连接的配置步骤
  • 《计算机组成原理》第 10 章 - 控制单元的设计
  • 用C#完成最小二乘法拟合平面方程,再计算点到面的距离
  • arcgis字段计算器中计算矢量面的每个点坐标
  • Vue-03 (调试工具Vue Devtools )
  • Go语言中的浮点数类型详解
  • 鸿蒙5开发宝藏案例分享---一多断点开发实践
  • 5分钟入门WPF和FluentValidation数据验证
  • 微信小程序获取手机号
  • 用nz-tabel写一个合并表格
  • JavaSE核心知识点04工具04-04(Git)
  • JS手写代码篇---手写promise.all
  • Linux基本指令篇 —— touch指令
  • html css js网页制作成品——HTML+CSS+js醇香咖啡屋网页设计(5页)附源码
  • 在ubuntu手动分区时,730GB的总空间,建议划分多少给根目录
  • 做配单ic去什么网站好/青岛官网seo方法
  • 一带一路网站建设规划书/中国企业500强最新排名
  • 西藏山南建设局网站/疫情放开死亡人数最新消息
  • web前端网站开发实例/靠谱的影视后期培训班
  • 人才招聘网网站策划方案/2023网站推广入口
  • 网页设计咨询/网站优化的方法与技巧