如何判断指定父节点的所有子节点是否均可删除(Java/SQL实现)
解决方案:判断树形节点是否可删除
核心规则
节点可删除的必要条件:
- 节点自身的
deletable字段值为1 - 该节点的**所有后代节点(子、孙、曾孙等)**的
deletable字段值全部为1
一、Java实现方案
优化思路
先把全量节点数据转成Map<Integer, List<Data1>>(key为parentId,value为对应子节点列表),避免递归时重复遍历全量数据提升效率。再通过递归逻辑,逐层验证当前节点及所有后代的可删除状态。
完整代码实现
// 假设Data1实体类已定义 class Data1 { private String name; private Integer id; private Integer deletable; private Integer parentId; // 标准getter方法 public Integer getId() { return id; } public Integer getDeletable() { return deletable; } public Integer getParentId() { return parentId; } // 构造方法 public Data1(String name, Integer id, Integer deletable, Integer parentId) { this.name = name; this.id = id; this.deletable = deletable; this.parentId = parentId; } } public class NodeDeleteChecker { public static boolean canDeleteNode(List<Data1> allNodes, Integer targetId) { // 1. 先校验目标节点自身状态 Data1 targetNode = allNodes.stream() .filter(node -> node.getId().equals(targetId)) .findFirst() .orElse(null); if (targetNode == null || targetNode.getDeletable() != 1) { return false; } // 2. 构建父子节点映射表 Map<Integer, List<Data1>> parentChildMap = new HashMap<>(); for (Data1 node : allNodes) { parentChildMap.computeIfAbsent(node.getParentId(), k -> new ArrayList<>()).add(node); } // 3. 递归校验所有后代节点 return checkAllDescendants(parentChildMap, targetId); } private static boolean checkAllDescendants(Map<Integer, List<Data1>> parentChildMap, Integer currentParentId) { List<Data1> children = parentChildMap.getOrDefault(currentParentId, Collections.emptyList()); for (Data1 child : children) { // 子节点自身不可删,直接返回false if (child.getDeletable() != 1) { return false; } // 递归校验子节点的后代,只要有一个分支不可删就返回false if (!checkAllDescendants(parentChildMap, child.getId())) { return false; } } // 所有子节点及后代都符合要求 return true; } // 使用示例 public static void main(String[] args) { List<Data1> nodes = Arrays.asList( new Data1("A", 1, 1, 0), new Data1("B1", 2, 1, 1), new Data1("B2", 3, 1, 1), new Data1("C1", 4, 0, 3), new Data1("C2", 5, 1, 3), new Data1("D1", 6, 1, 5) ); // 测试删除ID=3:返回false(因为C1不可删) System.out.println(canDeleteNode(nodes, 3)); // 测试删除ID=5:返回true(自身和D1都可删) System.out.println(canDeleteNode(nodes, 5)); } }
逻辑说明
- 先验证目标节点是否存在且自身可删除,不满足直接返回false
- 构建父子映射表,减少递归时的重复遍历操作
- 递归遍历每个子节点:
- 若子节点自身不可删除,直接终止校验返回false
- 递归检查该子节点的所有后代,只要有一个分支不满足,就返回false
- 所有分支校验通过后,返回true
二、SQL实现方案
如果数据库支持递归查询(如MySQL 8.0+、PostgreSQL、SQL Server),可以直接用SQL一次性查询目标节点的所有后代,统一验证状态。
示例SQL(MySQL)
-- 替换3为目标节点ID,查询该节点是否可删除 WITH RECURSIVE node_tree AS ( -- 初始节点:目标节点自身 SELECT id, deletable FROM Data1 WHERE id = 3 UNION ALL -- 递归查询所有后代节点 SELECT d.id, d.deletable FROM Data1 d JOIN node_tree nt ON d.parentId = nt.id ) -- 校验所有节点的deletable是否全为1,同时处理节点不存在的情况 SELECT CASE WHEN COUNT(*) = 0 THEN FALSE WHEN MIN(deletable) = 1 THEN TRUE ELSE FALSE END AS can_delete FROM node_tree;
逻辑说明
- 使用
WITH RECURSIVE递归获取目标节点及其所有后代 - 通过
MIN(deletable)判断所有节点的可删除状态:只要有一个节点deletable为0,MIN结果就是0 - 同时处理目标节点不存在的情况,返回false
内容的提问来源于stack exchange,提问作者Blaj Bogdan
相关产品推荐
相关产品推荐

