问题简介:
如图,1号节点的子节点3,是否能增加子节点6?不能!因为6的子节点2已有子节点3,如若增加,则导致成环。
如何实现新增节点时的环状检测?
思路:
- 维护一个dagMap,key为节点ID,value为下一层子节点ID以及子节点数量
- 新增时递归检测父节点是否在子节点的子中已经存在,存在则有环,不能新增
- 新增/删除时则增加/减少自己在父节点的子中的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;
}
}
}