【Easylive】convertLine2Tree 方法详解

【Easylive】项目常见问题解答(自用&持续更新中...) 汇总版

这是一个 将扁平列表转换为树形结构 的递归方法,常用于处理 分类目录、菜单、部门 等具有父子层级关系的数据。下面逐步解析其逻辑和设计思想。


1. 方法作用

输入 :扁平化的分类列表(List<CategoryInfo>),每个对象包含 categoryIdpCategoryId(父ID)。

输出 :树形结构的分类列表,每个节点的子分类挂在 children 属性下。

典型场景

数据库存储的是一维表结构(每行记录通过 pCategoryId 指向父节点),但前端需要树形结构展示。


2. 参数说明

参数名 类型 作用
dataList List<CategoryInfo> 扁平化的原始数据列表(包含所有节点,不区分层级)。
pid Integer 当前递归层级的父节点ID(首次调用时通常传 0null 表示根节点)。

3. 核心逻辑分步解析

(1) 初始化子节点列表

java 复制代码
List<CategoryInfo> children = new ArrayList<>();

• 为当前层级(pid 的子节点)准备一个空列表。

(2) 遍历所有节点

java 复制代码
for (CategoryInfo m : dataList) {
    // 检查当前节点是否属于当前父节点
    if (m.getCategoryId() != null && m.getpCategoryId() != null && m.getpCategoryId().equals(pid)) {
        // 递归处理子节点
        m.setChildren(convertLine2Tree(dataList, m.getCategoryId()));
        children.add(m);
    }
}

条件判断

找到所有 pCategoryId == pid 的节点(即父节点是 pid 的节点)。

递归调用

对每个符合条件的节点,继续查找其子节点(以 m.getCategoryId() 作为新的 pid)。

构建树形

将子节点列表设置到当前节点的 children 属性中。

(3) 返回结果

java 复制代码
return children;

• 返回当前层级的所有子节点(已递归包含所有后代节点)。


4. 示例演示

假设原始数据

categoryId pCategoryId name
1 0 电子产品
2 0 服装
3 1 手机
4 1 电脑
5 3 智能手机

调用过程

  1. 首次调用convertLine2Tree(dataList, 0)

    • 找到根节点(pCategoryId=0):[电子产品, 服装]

    • 对 电子产品 递归:

    ◦ 找到子节点(pCategoryId=1):[手机, 电脑]

    ◦ 对 手机 递归:

    ◦ 找到子节点(pCategoryId=3):[智能手机]

    智能手机 无子节点,递归终止。

    服装 无子节点,递归终止。

  2. 最终树形结构

    json 复制代码
    [
      {
        "categoryId": 1,
        "name": "电子产品",
        "children": [
          {
            "categoryId": 3,
            "name": "手机",
            "children": [
              {
                "categoryId": 5,
                "name": "智能手机",
                "children": []
              }
            ]
          },
          {
            "categoryId": 4,
            "name": "电脑",
            "children": []
          }
        ]
      },
      {
        "categoryId": 2,
        "name": "服装",
        "children": []
      }
    ]

5. 关键点分析

(1) 递归终止条件

• 隐含在 if 条件中:当没有节点的 pCategoryId 匹配当前 pid 时,递归结束。

• 无需显式判断,因为 children 会返回空列表。

(2) 时间复杂度

最坏情况 :O(n²)(每个节点遍历整个列表)。
优化方案

• 先用 Map<Integer, List<CategoryInfo>>pCategoryId 分组,可将时间优化到 O(n)。

• 示例:
java Map<Integer, List<CategoryInfo>> groupMap = dataList.stream() .collect(Collectors.groupingBy(CategoryInfo::getpCategoryId));

(3) 注意事项

数据需有序 :若原始数据是乱序的,可能漏掉深层节点。建议先按层级排序。

避免循环引用 :如 A→B→C→A 会导致无限递归。需确保数据无环。


6. 方法优化建议

(1) 使用 Map 加速查找

java 复制代码
private List<CategoryInfo> convertLine2Tree(List<CategoryInfo> dataList, Integer pid) {
    // 先按父ID分组
    Map<Integer, List<CategoryInfo>> groupMap = dataList.stream()
            .collect(Collectors.groupingBy(CategoryInfo::getpCategoryId));
    
    List<CategoryInfo> children = groupMap.getOrDefault(pid, new ArrayList<>());
    for (CategoryInfo m : children) {
        m.setChildren(convertLine2Tree(dataList, m.getCategoryId()));
    }
    return children;
}

(2) 支持空父节点

java 复制代码
if (pid == null) {
    pid = 0; // 默认根节点ID
}

7. 总结

核心思想 :通过递归将扁平列表转换为树形结构。

适用场景 :任何需要父子层级展示的数据(如分类、菜单、评论回复)。

优化方向 :使用 Map 分组减少遍历次数,确保数据无环。

相关推荐
jack_xu19 分钟前
经典大厂面试题——缓存穿透、缓存击穿、缓存雪崩
java·redis·后端
CHQIUU1 小时前
Java 设计模式心法之第4篇 - 单例 (Singleton) 的正确打开方式与避坑指南
java·单例模式·设计模式
碎梦归途2 小时前
23种设计模式-结构型模式之享元模式(Java版本)
java·开发语言·jvm·设计模式·享元模式
lozhyf2 小时前
Eureka搭建
java·spring cloud
幽络源小助理2 小时前
SpringBoot民宿管理系统开发实现
java·spring boot·springboot·民宿系统
东阳马生架构2 小时前
Nacos简介—1.Nacos使用简介
java
爱发飙的蜗牛2 小时前
springboot--web开发请求参数接收注解
java·spring boot·后端
码熔burning2 小时前
【MQ篇】RabbitMQ之工作队列模式!
java·分布式·rabbitmq·mq
优雅的落幕2 小时前
Spring--统一数据返回格式与统一异常处理
java·spring·状态模式
BillKu2 小时前
Spring Boot + MyBatis 动态字段更新方法
java·spring boot·mybatis