一、核心知识点概述
本案例通过递归算法实现树形结构的遍历,主要涉及以下知识点:
- 树形结构的递归遍历
- Set数据结构的去重特性
- 层级结果的合并逻辑
- 条件判断与递归终止条件
二、递归实现原理分析
举个例子
基础数据
const mockData = [{id: 1, labe: '父节点1', children: [{id:11,label:'子节点1',},{id:12,label:'子节点2',},{id:13,label:'子节点3',},],},{id: 2, labe: '父节点2', children: [{id:21,label:'子节点1',},{id:22,label:'子节点2',},{id:23,label:'子节点3',},],},{id: 3, labe: '父节点3', children: [{id: 31, label: '子节点1', children: [{id:311,label:'子节点1.1',},{id:312,label:'子节点1.2',},{id:313,label:'子节点1.3',},],},{id:32,label:'子节点2',},{id:33,label:'子节点3',},],},];const selectKey = [1,11,12,22];需求:根据给定选中的节点id值,自动填充其父级在节点id
1. 递归函数结构
constcollectAllParents=(nodes,checkedKeys)=>{constresult=newSet();nodes.forEach(item=>{// 基础判断:当前节点是否被选中if(checkedKeys.has(item.id))result.add(item.id);// 递归处理子节点if(item?.children?.length>0){constsubResult=collectAllParents(item.children,checkedKeys);// 合并子结果与当前节点if(subResult.size>0){result.add(item.id);// 父节点自动选中subResult.forEach(id=>result.add(id));}}});returnresult;};2. 递归终止条件
- 当节点无子节点(
item.children.length === 0)时,递归自然终止 - 当遍历完所有子节点后,返回当前层级的结果集
3. 递归执行流程
- 从根节点开始遍历
- 检查当前节点是否被选中
- 若存在子节点,递归处理子节点集合
- 合并子节点结果与当前节点结果
- 返回包含当前层级及子层级结果的集合
三、Set数据结构的作用
1. 去重特性
constcheckedKeys=newSet(selectKey);- 确保遍历过程中节点ID的唯一性
- 提供
O(1)时间复杂度的成员判断(has()方法)
2. 结果集的合并
subResult.forEach(id=>result.add(id));- 利用Set的自动去重特性合并多级结果
- 避免手动去重的复杂性
四、层级结果合并机制
1. 父子节点关联逻辑
当子节点被选中时:
if(subResult.size>0){result.add(item.id);// 自动选中父节点// 合并子节点结果}- 父节点自动被标记为选中
- 子结果集通过
forEach合并到父级结果
2. 多层级数据穿透
// 从根节点到最深层子节点的递归穿透constsubResult=collectAllParents(item.children,checkedKeys);- 实现自底向上的结果收集
- 确保所有父节点都被正确标记
五、条件判断逻辑
1. 当前节点选中判断
if(checkedKeys.has(item.id))result.add(item.id);- 直接判断当前节点是否在选中列表
2. 子节点结果判断
if(subResult.size>0){...}- 通过子结果集的大小判断是否存在被选中的子节点
六、 核心知识点
递归遍历每层涉及的变量值是相互独立的,在每一层收集之后进行合并整合