存储过程递归树结构实现(某一节点下所有子节点)三种方式

最近项目中碰到需要写递归,就特意实现了集中实现方式,总结一下~

情景:通过给出的机构id,得到该机构id以及所有的子机构信息,机构id是UUID;

通过三种方式去实现,亲自实现过,可直接用:

第一种:通过多次操作数据库获得所有子机构信息。实现如下:

/**
	 * 递归获取某个机构id下面的所有子机构
	 * @param comTreeBeanHashSet  节点集合
	 * @param mechanismId  当前机构ID
	 */
	private void findChildMechanisms(Set<ComTreeBean> comTreeBeanHashSet, String mechanismId) {

		ComTreeBean dep=comTreeDao.findByMechanismId(mechanismId);
		List<ComTreeBean> comTreeBeans = new ArrayList<ComTreeBean>();
		comTreeBeans.add(dep);
		/**
		 * 加入当前机构
		 */
		comTreeBeanHashSet.addAll(comTreeBeans.stream().collect(Collectors.toList()));
		/**
		 * 获取子机构
		 */
		List<ComTreeBean> comTreeBeanPars = comTreeDao.findByParentId(mechanismId);
		for (ComTreeBean d : comTreeBeanPars) {
			/**
			 * 递归子单位
			 */
			findChildMechanisms(comTreeBeanHashSet, d.getUid());
		}
	}

第二种:不会多次操作数据库,通过一次查询,获取所有机构树信息,再从当前机构去递归获取所有子机构信息

    //子节点集合
    List<ComTreeBean> childMenu = new ArrayList<ComTreeBean>;

    /**
	 * 获取某个父节点下面的所有子节点
	 * @param menuList
	 * @param id 当前机构id
	 * @return
	 */
	public static List<ComTreeBean> treeMenuList(List<ComTreeBean> childMenu,             
      List<ComTreeBean> menuList, String id){
		for(ComTreeBean mu: menuList){
			//遍历出父id等于参数的id,add进子节点集合
			if(id.equals(mu.getParComUid())){
				//递归遍历下一级
				treeMenuList(childMenu,menuList,mu.getUid());
				childMenu.add(mu);
			}
		}
		return childMenu;
	}

直接使用能获取所有子机构信息,但是不能获取传入机构信息,如果想保留当前传入id机构,在初始化子节点集合时放入当前机构即可,即为:

        //子节点集合
		List<ComTreeBean> childMenu = comTreeBeanList.stream().filter(comTreeBean ->     
            pid.equals(comTreeBean.getUid())).collect(Collectors.toList());

当然,这两种方式都是机构树的数据不是很大,考虑到如果其他情况下,比如数据量大,就考虑使用第三种方式,通过创建存储过程实现,我也将其实现了一遍,表实例就不给出了,具体实现如下,可自己创建表实例实验:

第三种:存储过程

首先定义执行递归操作的存储过程,如下

-- 首先定义执行递归操作的存储过程:findChildList

CREATE PROCEDURE findChildList(IN id varchar(100))
BEGIN
DECLARE v_dep varchar(100) DEFAULT -1;
DECLARE done varchar(100) DEFAULT 0;
DECLARE C_dep CURSOR FOR SELECT d.id FROM T_COM_INFO d WHERE d.par_com_uid = id;
DECLARE CONTINUE HANDLER FOR NOT found set done=1;
SET @@max_sp_recursion_depth = 10;
INSERT INTO tmp_Dep VALUES (id);
OPEN C_dep;
FETCH C_dep INTO v_dep;
WHILE (done =0)
DO
	CALL findChildList(v_dep);
	FETCH C_dep INTO v_dep;
END WHILE;
END

然后定义调用递归操作的存储过程,如下

-- 再定义调用递归操作的存储过程:findDepList

CREATE PROCEDURE findDepList(IN id varchar(100))
BEGIN

DROP TEMPORARY TABLE IF EXISTS tmp_Dep;
CREATE TEMPORARY TABLE tmp_Dep(depId varchar(100));
DELETE FROM tmp_Dep;
CALL findChildList(id);
SELECT distinct tmp_Dep.depId,T_COM_INFO.com_name FROM tmp_Dep,T_COM_INFO where tmp_Dep.depId = T_COM_INFO.id  order by depId;
END

调用存储过程及删除存储过程,如下:

call findDepList('45e9b12d-165f6037fad-9c1534b1e8dbb5a0c0ec3f70d24f9627')

drop procedure if exists findChildList

drop procedure if exists findDepList

具体就是这样,顺便给出本人写测试时,id为int类型的存储过程,如下

-- 首先定义执行递归操作的存储过程:findChildList

CREATE PROCEDURE findChildList(IN id BIGINT)
BEGIN
DECLARE v_dep integer DEFAULT -1;
DECLARE done integer DEFAULT 0;
DECLARE C_dep CURSOR FOR SELECT d.id FROM treenodes d WHERE d.pid = id;
DECLARE CONTINUE HANDLER FOR NOT found set done=1;
SET @@max_sp_recursion_depth = 10;
INSERT INTO tmp_Dep VALUES (id);
OPEN C_dep;
FETCH C_dep INTO v_dep;
WHILE (done =0)
DO
	CALL findChildList(v_dep);
	FETCH C_dep INTO v_dep;
END WHILE;
END

-- 再定义调用递归操作的存储过程:findDepList

CREATE PROCEDURE findDepList(IN id BIGINT)
BEGIN

DROP TEMPORARY TABLE IF EXISTS tmp_Dep;
CREATE TEMPORARY TABLE tmp_Dep(depId INTEGER);
DELETE FROM tmp_Dep;
CALL findChildList(id);
SELECT distinct tmp_Dep.depId,treenodes.nodename FROM tmp_Dep,treenodes where tmp_Dep.depId = treenodes.id  order by depId;
END


drop procedure if exists findChildList

drop procedure if exists findDepList


call findDepList(3)

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 以下是一个示例的 JavaScript 代码,实现递归查找树形结构中某一节点的功能。 ```javascript function findNode(node, targetId) { if (node.id === targetId) { return node; } if (node.children) { for (let i = 0; i < node.children.length; i++) { let found = findNode(node.children[i], targetId); if (found) { return found; } } } return null; } ``` 这段代码中,`findNode` 是一个递归函数,它接受两个参数:当前节点和目标节点的 ID。在函数中,如果当前节点的 ID 与目标节点的 ID 相同,则返回当前节点。否则,如果当前节点子节点,则对于每一个子节点都调用 `findNode` 函数,并检查它的返回值。如果找到了目标节点,则返回该节点;否则返回 null。 这个示例假设你的树形结构是一个对象, 这个对象有一个ID和children属性, 也可以根据具体需要修改成其他的. ### 回答2: 下面是一个使用递归查找树形结构下某一节点JavaScript 函数: ```javascript function findNode(tree, targetId) { // 遍历树的函数 function traverseNode(node) { // 如果当前节点的id等于目标id,则返回当前节点 if (node.id === targetId) { return node; } // 遍历当前节点子节点 for (let i = 0; i < node.children.length; i++) { // 递归调用遍历函数,查找子节点 const foundNode = traverseNode(node.children[i]); // 如果找到了目标节点,则返回该节点 if (foundNode !== null) { return foundNode; } } // 如果没有找到目标节点,则返回null return null; } // 调用递归函数,从根节点开始查找 return traverseNode(tree); } ``` 这个函数接收两个参数,`tree` 表示树形结构的根节点,`targetId` 表示目标节点的id。首先定义了一个内部递归函数 `traverseNode`,用来遍历节点并查找目标节点。在遍历函数中,首先检查当前节点的id是否等于目标id,如果是则返回当前节点。然后遍历当前节点子节点,对每个子节点递归调用遍历函数,查找子节点中是否存在目标节点。如果找到,则返回该节点。如果遍历完所有子节点都没有找到目标节点,则返回null。最后,在外部调用中,调用遍历函数,从根节点开始查找。如果找到目标节点,则返回该节点,否则返回null。 ### 回答3: JavaScript递归查找树形结构下的某一节点可以通过以下步骤实现: 1. 首先,定义一个递归函数,接收两个参数:要查询的节点id和一个树形结构的数据。假设我们的树形结构数据是一个对象数组,每个对象都有一个唯一的id和一个children属性,存储了该节点子节点。 2. 在递归函数中,首先遍历树形结构数据数组。可以使用for循环或者Array.prototype.forEach()方法来实现。 3. 对于每一个数据对象,首先判断当前节点的id是否等于要查询的节点id。如果等于,则找到了目标节点,可以返回该节点。 4. 如果当前节点的id不等于要查询的节点id,则继续递归调用该函数,在当前节点子节点(children)数组上进行遍历,传入要查询的节点id和子节点数组作为参数。 5. 对于每一个子节点对象,再次执行步骤3和步骤4,直到遍历完整个树形结构,或者找到目标节点为止。 6. 如果在整个树形结构中未找到目标节点,则返回null或者其他指定的未找到标识。 示例代码如下: ```javascript function findNode(id, data) { for (var i = 0; i < data.length; i++) { if (data[i].id === id) { return data[i]; // 找到目标节点 } else if (data[i].children && data[i].children.length > 0) { var result = findNode(id, data[i].children); // 递归子节点中查找 if (result) { return result; // 在子节点中找到了目标节点 } } } return null; // 未找到目标节点 } ``` 以上代码中,我们传入要查询的节点id和树形结构数据数组,例如`findNode(3, data)`,其中`data`是树形结构数据。函数会递归查找并返回具有指定id的节点对象,如果找不到则返回null。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值