递归算法遍历树

本文介绍了如何在实际工作中运用递归算法解决企业架构需求,包括通过父节点id查找父节点名称、根据用户权限筛选节点、以及根据设备归属添加到树结构中。递归终止条件和三步操作法是关键概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目前工作中遇到一些需求,运用递归算法解决需求。

递归三步曲

  1. 递归终止条件
  2. 一级递归做什么
  3. 返回上一级的返回值是什么

树结构如下

tree:[{
		id:1,
		name:'公司A',
		parent_id:'',
		children:[{
			id:2,
			name:'公司A-一级子公司1',
			parent_id:1,
			children:[{
				id:3,
				name:'公司A-二级子公司1',
				parent_id:2,
			}]
		},
		{
			id:4,
			name:'公司A-一级子公司2',
			parent_id:1,
			children:[{
				id:5,
				name:'公司A-二级子公司2',
				parent_id:4,
			}]
		}]
	}]

递归运用

1.有父节点id查找父节点name

由于子节点有个parent_id,利用此属性查找孩子节点的父节点名称。
思路:

  • 递归截止条件:当子节点的parent_id==节点id时截止。
  • 一级递归做什么:如果当前节点有子节点,那么递归子节点
  • 返回什么:查找的是name,返回的是节点的name
getParentName(data, parent_id) {
    for (let i = 0; i < data.length; i++) {
        let item = data[i];
        if (item.id === parent_id) {
            return item.name;
        } else {
            // item.children 不等于 undefined && item.children.length 大于 0 时
            if (item.children && item.children.length > 0) {
                let res = this.getParentName(item.children, parent_id);
                // 当 res = undefined 时不会进入判断中
                // 也就是不会return
                if (res) return res;
            }
        }
    }
},

2.节点筛选,未满足条件的节点删除

需求:用户拥有一些公司权限,保存拥有的公司删除未拥有的公司。
用户公司的数据结构:

userCompany:[{
	user_id:1,
	company_id:1
},{
	user_id:1,
	company_id:2
},{
	user_id:1,
	company_id:4
}]

思路:

  • 递归截止条件:如果在用户公司数组中未找到公司并且无孩子,那么可删除
  • 一级递归做什么:1.找到并且有孩子则继续遍历。2.未找到但有孩子继续遍历,注意:如果孩子节点全被删除那么此节点可删除
  • 返回什么:没有返回值,
 ergodicCompanyTree(tree){
    for(var i=0;i<tree.length;i++){
        let item=tree[i];
        let company=this.userCompany.find(val=>val.company_id==item.id);
        if(company==undefined){  
            if(item.children&&item.children.length>0){  //未找到并且有孩子
               this.ergodicCompanyTree(item.children);
                //如果孩子节点全被删除,则此可删除
                if(item.children&&item.children.length<1){
                    tree.splice(i--,1)
                }
            }else{   //未找到且无孩子
                tree.splice(i--,1)
            }
        }else{
            if(item.children&&item.children.length>0){  //找到并且有孩子
                this.ergodicCompanyTree(item.children);
            }else{   //找到但无孩子                
            }
        }
    }
},

3.节点添加,满足条件的节点添加入树

每个公司有多个设备,一个设备所属一个公司,遍历设备列表,将设备节点添加至公司树。
设备数据结构如下:

device:[{
	device_id:1,
	company_id:1
},{
	device_id:2,
	company_id:1
},{
	device_id:3,
	company_id:3
}]

思路:

  • 递归截止条件:找到设备所属公司将设备对象插入此节点的下一级节点children,若无children则新建有则直接添加
  • 一级递归做什么: 未找到设备所属公司并且有孩子节点则递归,如果孩子节点找到了则返回true
  • 返回什么:如果找到了则返回true
/*
  递归遍历公司树,查找到设备所属公司的那一级节点并将设备对象插入此节点的下一级节点。 
*/
ergodicCompanyTree(device,tree){
	for(let i=0;i<tree.length;i++){
		let item=tree[i]
		if(item.company_id==device.company_id){  //找到公司节点,更改设备公司id为设备id+"_"(因为树的node-key为公司id,这里做的更改是为了避免id重复),公司name为设备name(树的lable为公司name,这里做的更改是页面查看节点为设备名而非公司名)
			device.company_name=device.name;  
			device.company_id=device.device_id+"_"
			item.children?item.children.push(device):(item.children=[],item.children.push(device))
			return true
		}else{
			if(item.children && item.children.length>0){
				let res=this.ergodicCompanyTree(device,item.children)
				if(res){
					return res
				} 
			}
		}
	}
},

总结

1.牢记递归三步曲,运用时搞清楚这三步
2.多练习多测试。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值