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

相关推荐
木头没有瓜9 分钟前
idea离线安装插件
java·ide·intellij-idea
llwszx19 分钟前
Spring中DelayQueue深度解析:从原理到实战(附结构图解析)
java·后端·spring·delayqueue·延迟任务
述雾学java34 分钟前
Spring Cloud Feign 整合 Sentinel 实现服务降级与熔断保护
java·spring cloud·sentinel
保持学习ing34 分钟前
苍穹外卖day3--公共字段填充+新增菜品
java·阿里云·实战·springboot·前后端·外卖项目·阿里云文件存储
77qqqiqi1 小时前
正则表达式
java·后端·正则表达式
厦门德仔1 小时前
【WPF】WPF(样式)
android·java·wpf
大春儿的试验田1 小时前
高并发收藏功能设计:Redis异步同步与定时补偿机制详解
java·数据库·redis·学习·缓存
Gappsong8741 小时前
【Linux学习】Linux安装并配置Redis
java·linux·运维·网络安全
hqxstudying1 小时前
Redis为什么是单线程
java·redis
RainbowSea2 小时前
NVM 切换 Node 版本工具的超详细安装说明
java·前端