You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何判断指定父节点的所有子节点是否均可删除(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));
    }
}

逻辑说明

  1. 先验证目标节点是否存在且自身可删除,不满足直接返回false
  2. 构建父子映射表,减少递归时的重复遍历操作
  3. 递归遍历每个子节点:
    • 若子节点自身不可删除,直接终止校验返回false
    • 递归检查该子节点的所有后代,只要有一个分支不满足,就返回false
  4. 所有分支校验通过后,返回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;

逻辑说明

  1. 使用WITH RECURSIVE递归获取目标节点及其所有后代
  2. 通过MIN(deletable)判断所有节点的可删除状态:只要有一个节点deletable为0,MIN结果就是0
  3. 同时处理目标节点不存在的情况,返回false

内容的提问来源于stack exchange,提问作者Blaj Bogdan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 07:33:19