【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 分组减少遍历次数,确保数据无环。

相关推荐
圈圈编码2 分钟前
Spring Task 定时任务
java·前端·spring
俏布斯14 分钟前
算法日常记录
java·算法·leetcode
276695829219 分钟前
美团民宿 mtgsig 小程序 mtgsig1.2 分析
java·python·小程序·美团·mtgsig·mtgsig1.2·美团民宿
爱的叹息20 分钟前
Java 连接 Redis 的驱动(Jedis、Lettuce、Redisson、Spring Data Redis)分类及对比
java·redis·spring
程序猿chen30 分钟前
《JVM考古现场(十五):熵火燎原——从量子递归到热寂晶壁的代码涅槃》
java·jvm·git·后端·java-ee·区块链·量子计算
松韬1 小时前
Spring + Redisson:从 0 到 1 搭建高可用分布式缓存系统
java·redis·分布式·spring·缓存
绝顶少年1 小时前
Spring Boot 注解:深度解析与应用场景
java·spring boot·后端
心灵宝贝1 小时前
Tomcat 部署 Jenkins.war 详细教程(含常见问题解决)
java·tomcat·jenkins
天上掉下来个程小白1 小时前
Redis-14.在Java中操作Redis-Spring Data Redis使用方式-操作列表类型的数据
java·redis·spring·springboot·苍穹外卖
ゞ 正在缓冲99%…2 小时前
leetcode22.括号生成
java·算法·leetcode·回溯