【Easylive】项目常见问题解答(自用&持续更新中…) 汇总版
这是一个 将扁平列表转换为树形结构 的递归方法,常用于处理 分类目录、菜单、部门 等具有父子层级关系的数据。下面逐步解析其逻辑和设计思想。
1. 方法作用
• 输入:扁平化的分类列表(List<CategoryInfo>
),每个对象包含 categoryId
和 pCategoryId
(父ID)。
• 输出:树形结构的分类列表,每个节点的子分类挂在 children
属性下。
• 典型场景:
数据库存储的是一维表结构(每行记录通过 pCategoryId
指向父节点),但前端需要树形结构展示。
2. 参数说明
参数名 | 类型 | 作用 |
---|---|---|
dataList | List<CategoryInfo> | 扁平化的原始数据列表(包含所有节点,不区分层级)。 |
pid | Integer | 当前递归层级的父节点ID(首次调用时通常传 0 或 null 表示根节点)。 |
3. 核心逻辑分步解析
(1) 初始化子节点列表
List<CategoryInfo> children = new ArrayList<>();
• 为当前层级(pid
的子节点)准备一个空列表。
(2) 遍历所有节点
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) 返回结果
return children;
• 返回当前层级的所有子节点(已递归包含所有后代节点)。
4. 示例演示
假设原始数据
categoryId | pCategoryId | name |
---|---|---|
1 | 0 | 电子产品 |
2 | 0 | 服装 |
3 | 1 | 手机 |
4 | 1 | 电脑 |
5 | 3 | 智能手机 |
调用过程
-
首次调用:
convertLine2Tree(dataList, 0)
• 找到根节点(pCategoryId=0
):[电子产品, 服装]
• 对电子产品
递归:
◦ 找到子节点(pCategoryId=1
):[手机, 电脑]
◦ 对手机
递归:
◦ 找到子节点(pCategoryId=3
):[智能手机]
◦智能手机
无子节点,递归终止。
•服装
无子节点,递归终止。 -
最终树形结构:
[{"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 加速查找
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) 支持空父节点
if (pid == null) {pid = 0; // 默认根节点ID
}
7. 总结
• 核心思想:通过递归将扁平列表转换为树形结构。
• 适用场景:任何需要父子层级展示的数据(如分类、菜单、评论回复)。
• 优化方向:使用 Map
分组减少遍历次数,确保数据无环。