有向无环图在新增节点时的环状检测

在这里插入图片描述

问题简介:

如图,1号节点的子节点3,是否能增加子节点6?不能!因为6的子节点2已有子节点3,如若增加,则导致成环。

如何实现新增节点时的环状检测?

思路:

  1. 维护一个dagMap,key为节点ID,value为下一层子节点ID以及子节点数量
  2. 新增时递归检测父节点是否在子节点的子中已经存在,存在则有环,不能新增
  3. 新增/删除时则增加/减少自己在父节点的子中的count

Code:

Talk is cheap, show me the code…

import java.util.*;

public class NodeCircle {
    public static Map<Long, Map<Long, Integer>> nextMapMap = new HashMap<>();

    public static void main(String[] args) {
        List<Node> nodes = Arrays.asList(
                new Node(1L, "2,3"),
                new Node(2L, "5,3"),
                new Node(3L, null),
                new Node(4L, null),
                new Node(5L, null),
                new Node(6L, "2"),
                new Node(7L, "3"));
        for (Node node : nodes) {
            if (node.getSonIds() != null) {
                String[] sonIdStrs = node.getSonIds().split(",");
                for (String sonIdStr : sonIdStrs) {
                    Long sonId = Long.parseLong(sonIdStr);
                    Map<Long, Integer> nextMap = nextMapMap.computeIfAbsent(node.getId(), k -> new HashMap<>());
                    int nextCount = nextMap.computeIfAbsent(sonId, k -> 0);
                    nextCount += 1;
                    nextMap.put(sonId, nextCount);
                }
            }
        }
        System.out.println(nextMapMap);
        link(3L, 6L);
        unlink(6L, 2L);
        System.out.println(nextMapMap);
        link(3L, 6L);
        System.out.println(nextMapMap);
        link(1L, 2L);
        System.out.println(nextMapMap);
    }

    public synchronized static boolean haveCircle(Long nodeId, Long linkId) {
        if (nodeId.equals(linkId)) {
            return true;
        }
        Map<Long, Integer> linkNextMap = nextMapMap.get(linkId);
        if (linkNextMap == null || linkNextMap.isEmpty()) {
            return false;
        }
        Set<Long> linkNext = linkNextMap.keySet();
        if (linkNext.contains(nodeId)) {
            return true;
        }
        for (Long next : linkNext) {
            if (haveCircle(nodeId, next)) {
                return true;
            }
        }
        return false;
    }

    /*
     * nodeId next add linkId count
     */
    public synchronized static void link(Long nodeId, Long linkId) {
        if (haveCircle(nodeId, linkId)) {
            System.out.println("have circle nodeId:" + nodeId + " linkId:" + linkId);
            return;
        }
        Map<Long, Integer> nodeNextMap = nextMapMap.computeIfAbsent(nodeId, k -> new HashMap<>());
        Integer nodeNextCount = nodeNextMap.computeIfAbsent(linkId, k -> 0);
        nodeNextMap.put(linkId, nodeNextCount + 1);
    }

    /*
     * nodeId next reduce linkId count
     */
    public synchronized static void unlink(Long nodeId, Long linkId) {
        Map<Long, Integer> nodeNextMap = nextMapMap.computeIfAbsent(nodeId, k -> new HashMap<>());
        int nodeNextCount = nodeNextMap.computeIfAbsent(linkId, k -> 0);
        if (nodeNextCount <= 1) {
            nodeNextMap.remove(linkId);
            if (nodeNextMap.isEmpty()) {
                nextMapMap.remove(nodeId);
            }
        } else {
            nodeNextMap.put(linkId, nodeNextCount - 1);
        }
    }

    public static class Node {

        public Long getId() {
            return id;
        }

        public String getSonIds() {
            return sonIds;
        }

        private final Long id;
        private final String sonIds;

        public Node(Long id, String sonIds) {
            this.id = id;
            this.sonIds = sonIds;
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值