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

Java 树形结构,根据名称搜索

一、需求

项目中有个树形列表(三层结构),想根据结构中的名称进行搜索,输出的结果依然保持树形结构。结构如下:
在这里插入图片描述

二、代码

import lombok.Data;import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;@Data
public class ProductCategoryRespVO {private Long id;private Long parentId;private String name;private String picUrl;private Integer sort;private Integer status;private String description;private LocalDateTime createTime;private Integer level;// 子分类列表private List<ProductCategoryRespVO> children = new ArrayList<>();public ProductCategoryRespVO(Long id, Long parentId, String name, String picUrl, Integer sort, Integer status, String description, LocalDateTime createTime, Integer level) {this.id = id;this.parentId = parentId;this.name = name;this.picUrl = picUrl;this.sort = sort;this.status = status;this.description = description;this.createTime = createTime;this.level = level;this.children = new ArrayList<>();}public void addChild(ProductCategoryRespVO child) {this.children.add(child);}
}

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;public class TreeUtil {// 搜索上下文类,用于存储搜索路径static class SearchContext {ProductCategoryRespVO level1Node = null;ProductCategoryRespVO level2Node = null;ProductCategoryRespVO matchedNode = null;}// 处理分类数组的搜索方法public static List<ProductCategoryRespVO> searchCategoryList(List<ProductCategoryRespVO> categories, String searchName) {if (CollectionUtils.isEmpty(categories) || StringUtils.isEmpty(searchName)) {return new ArrayList<>();}List<ProductCategoryRespVO> resultList = new ArrayList<>();for (ProductCategoryRespVO root : categories) {ProductCategoryRespVO result = searchCategoryTree(root, searchName);if (result != null) {resultList.add(result);}}return resultList;}// 搜索单个树的方法public static ProductCategoryRespVO searchCategoryTree(ProductCategoryRespVO root, String searchName) {SearchContext context = new SearchContext();// 查找匹配节点并记录路径findMatchedNode(root, searchName, context);// 根据匹配节点的层级返回不同的树形结构if (context.matchedNode == null) {return null; // 未找到匹配节点}if (context.matchedNode.getLevel() == 1) {// 命中level1节点,返回完整节点及其子节点return cloneNodeWithChildren(context.matchedNode);} else if (context.matchedNode.getLevel() == 2) {// 命中level2节点,返回其父节点(level1)和自身及其子节点ProductCategoryRespVO level1Clone = cloneNodeWithoutChildren(context.level1Node);ProductCategoryRespVO level2Clone = cloneNodeWithChildren(context.matchedNode);level1Clone.getChildren().add(level2Clone);return level1Clone;} else if (context.matchedNode.getLevel() == 3) {// 命中level3节点,返回其祖父节点(level1)、父节点(level2)和自身ProductCategoryRespVO level1Clone = cloneNodeWithoutChildren(context.level1Node);ProductCategoryRespVO level2Clone = cloneNodeWithoutChildren(context.level2Node);ProductCategoryRespVO level3Clone = cloneNodeWithChildren(context.matchedNode);level2Clone.getChildren().add(level3Clone);level1Clone.getChildren().add(level2Clone);return level1Clone;}return null;}// 递归查找匹配节点并记录路径private static void findMatchedNode(ProductCategoryRespVO node, String searchName, SearchContext context) {if (node == null) return;// 记录路径if (node.getLevel() == 1) {context.level1Node = node;context.level2Node = null; // 重置level2节点,因为进入了新的level1节点} else if (node.getLevel() == 2) {context.level2Node = node;}//        // 检查当前节点是否匹配
//        if (node.getName().equals(searchName)) {
//            context.matchedNode = node;
//            return;
//        }// 检查当前节点是否匹配if (node.getName().contains(searchName)) {context.matchedNode = node;return;}// 递归搜索子节点for (ProductCategoryRespVO child : node.getChildren()) {findMatchedNode(child, searchName, context);// 如果已经找到匹配节点,直接返回if (context.matchedNode != null) {return;}}}// 克隆节点但不包含子节点private static ProductCategoryRespVO cloneNodeWithoutChildren(ProductCategoryRespVO original) {ProductCategoryRespVO clone = new ProductCategoryRespVO(original.getId(),original.getParentId(),original.getName(),original.getPicUrl(),original.getSort(),original.getStatus(),original.getDescription(),original.getCreateTime(),original.getLevel());return clone;}// 克隆节点及其所有子节点private static ProductCategoryRespVO cloneNodeWithChildren(ProductCategoryRespVO original) {ProductCategoryRespVO clone = cloneNodeWithoutChildren(original);for (ProductCategoryRespVO child : original.getChildren()) {clone.addChild(cloneNodeWithChildren(child));}return clone;}// 示例用法public static void main(String[] args) {// 构建示例树结构 - 女装ProductCategoryRespVO womenRoot = new ProductCategoryRespVO(16L, 0L, "女装", "url", 1, 0, null, LocalDateTime.now(), 1);ProductCategoryRespVO womenTop = new ProductCategoryRespVO(17L, 16L, "上衣", "url", 1, 0, null, LocalDateTime.now(), 2);ProductCategoryRespVO womenVest = new ProductCategoryRespVO(21L, 17L, "背心", "url", 1, 0, null, LocalDateTime.now(), 3);ProductCategoryRespVO womenCoat = new ProductCategoryRespVO(23L, 17L, "外套", "url", 1, 0, null, LocalDateTime.now(), 3);womenRoot.addChild(womenTop);womenTop.addChild(womenVest);womenTop.addChild(womenCoat);// 构建示例树结构 - 男装ProductCategoryRespVO menRoot = new ProductCategoryRespVO(163L, 0L, "男装", "url", 1, 0, null, LocalDateTime.now(), 1);ProductCategoryRespVO menTop = new ProductCategoryRespVO(173L, 163L, "上衣", "url", 1, 0, null, LocalDateTime.now(), 2);ProductCategoryRespVO menVest = new ProductCategoryRespVO(213L, 173L, "背心", "url", 1, 0, null, LocalDateTime.now(), 3);ProductCategoryRespVO menCoat = new ProductCategoryRespVO(233L, 173L, "外套", "url", 1, 0, null, LocalDateTime.now(), 3);menRoot.addChild(menTop);menTop.addChild(menVest);menTop.addChild(menCoat);// 创建分类数组List<ProductCategoryRespVO> categoryList = new ArrayList<>();categoryList.add(womenRoot);categoryList.add(menRoot);// 搜索示例System.out.println("搜索 '女装':");List<ProductCategoryRespVO> result1 = searchCategoryList(categoryList, "女装");printResultList(result1);System.out.println("\n搜索 '上衣':");List<ProductCategoryRespVO> result2 = searchCategoryList(categoryList, "上衣");printResultList(result2);System.out.println("\n搜索 '背心':");List<ProductCategoryRespVO> result3 = searchCategoryList(categoryList, "背心");printResultList(result3);}// 辅助方法:打印搜索结果列表private static void printResultList(List<ProductCategoryRespVO> resultList) {if (resultList.isEmpty()) {System.out.println("未找到匹配的分类");return;}for (ProductCategoryRespVO root : resultList) {printTree(root, 0);System.out.println(); // 空行分隔不同的树}}// 辅助方法:打印树结构private static void printTree(ProductCategoryRespVO node, int level) {if (node == null) return;StringBuilder indent = new StringBuilder();for (int i = 0; i < level; i++) {indent.append("  ");}System.out.println(indent + node.getName() + " (Level " + node.getLevel() + ")");for (ProductCategoryRespVO child : node.getChildren()) {printTree(child, level + 1);}}}

三、测试结果

1、搜索“女装”,展示全部,结果如下:
在这里插入图片描述
2、搜索“裙装”,,展示“裙装”的上下节点数据,结果如下:
在这里插入图片描述
3、搜索“T恤”,,展示“T恤”的上下节点数据,结果如下:
在这里插入图片描述

http://www.xdnf.cn/news/9116.html

相关文章:

  • 医疗基础大模型在临床工作流程中的应用
  • 【Linux系统】Linux基础指令(一)
  • Node.js全局变量详解:__filename与__dirname
  • 小白场成长之路-计算机网络(三)
  • 深度学习入门(十三):加深网络
  • 【通用智能体】Dify API 文件上传功能: 两种传参方式的API传参方式
  • 《算法笔记》13.2小节——专题扩展->树状数组(BIT) 问题 D: 数列-训练套题T10T3
  • ArcGIS Pro 3.4 二次开发 - 几何引擎
  • AI时代新词-零样本学习(Zero-Shot Learning):AI的未来趋势
  • Queue 与 Deque 有什么区别?
  • FFMPEG-FLV-MUX编码
  • 洛谷 P3374 【模板】树状数组 1(线段树解法)
  • 【小白AI教程】大模型知识扫盲通识
  • 图片文件未正确加载​—— Webpack 无法正确解析图片,生成了一个空的 Base64 URL
  • 人工智能100问☞第33问:什么是计算机视觉?
  • 力扣HOT100之回溯:17. 电话号码的字母组合
  • MyBatis 动态 SQL 详解:灵活构建强大查询
  • 开源 FcDesigner 表单设计器组件事件详解
  • JavaScript面试题之深浅拷贝
  • PBX、IP PBX、FXO 、FXS 、VOIP、SIP 的概念解析以及关系
  • SpringAI(GA):Tool工具整合—快速上手
  • [7-1] ADC模数转换器 江协科技学习笔记(14个知识点)
  • 开源软件协议大白话分类指南
  • [yolov11改进系列]基于yolov11引入自注意力与卷积混合模块ACmix提高FPS+检测效率python源码+训练源码
  • 常见算法题目4 - 给定一个字符串,判断是否为有效的括号
  • 鸿蒙桌面快捷方式开发
  • 进程通信(管道,共享内存实现)
  • 【unity游戏开发——编辑器扩展】Gizmos可视化辅助工具
  • Leetcode 1924. 安装栅栏 II
  • RabbitMQ 集群与高可用方案设计(二)