package demo; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.commons.collections.CollectionUtils; import org.junit.Test; import java.util.*; import java.util.stream.Collectors; public class TreeTest { /** * 获取所有节点所有子节点列表 * * @throws Exception 当json序列化失败时抛出异常 */ @Test public void test1() throws Exception { //组装数据 TreeNode node1 = new TreeNode(1, 0, "根节点1"); TreeNode node2 = new TreeNode(2, 1, "二级节点1"); TreeNode node3 = new TreeNode(3, 1, "二级节点2"); TreeNode node4 = new TreeNode(4, 2, "三级节点1"); TreeNode node5 = new TreeNode(5, 3, "三级节点2"); TreeNode node6 = new TreeNode(6, 3, "根节点2"); TreeNode node7 = new TreeNode(7, 5, "二级节点1"); TreeNode node8 = new TreeNode(8, 6, "二级节点2"); TreeNode node9 = new TreeNode(9, 7, "三级节点1"); TreeNode node10 = new TreeNode(10, 8, "三级节点2"); List<TreeNode> nodes = Arrays.asList(node1,node2,node3,node4,node5,node6,node7,node8,node9,node10); //将list转为map,以pid为key组装子节点集合 Map<Integer, Set<TreeNode>> childrenNodeMap = nodes.stream().collect(Collectors.groupingBy(TreeNode::getPid, Collectors.toSet())); //将list转为map,存储key为id,value为node的map Map<Integer, TreeNode> allNodeMap = nodes.stream().collect(Collectors.toMap(TreeNode::getId, node -> node)); //获取没有子节点的节点信息放入队列 Set<Integer> keySet = childrenNodeMap.keySet(); Deque<Integer> nodeDeque = nodes.stream().map(TreeNode::getId) .filter(o -> !keySet.contains(o)).collect(Collectors.toCollection(ArrayDeque::new)); Integer currentNodeId; while ((currentNodeId = nodeDeque.pollFirst()) != null) { //获取当前节点 TreeNode node = allNodeMap.get(currentNodeId); if (node != null) { //获取父节点ID int pid = node.getPid(); //将当前节点得所有子节点赋值给父节点 Set<TreeNode> nodeList = childrenNodeMap.get(currentNodeId); if (CollectionUtils.isNotEmpty(nodeList)) { //使用set去重 childrenNodeMap.get(pid).addAll(nodeList); } //父节点入列 nodeDeque.addLast(pid); } } //测试 ObjectMapper objectMapper = new ObjectMapper(); String s = objectMapper.writeValueAsString(childrenNodeMap); System.out.println(s); } /** * 通过某个节点获取其所有子节点 */ @Test public void test2() { //组装数据 TreeNode node1 = new TreeNode(1, 0, "根节点1"); TreeNode node2 = new TreeNode(2, 1, "二级节点1"); TreeNode node3 = new TreeNode(3, 1, "二级节点2"); TreeNode node4 = new TreeNode(4, 2, "三级节点1"); TreeNode node5 = new TreeNode(5, 3, "三级节点2"); TreeNode node6 = new TreeNode(6, 3, "根节点2"); TreeNode node7 = new TreeNode(7, 5, "二级节点1"); TreeNode node8 = new TreeNode(8, 6, "二级节点2"); TreeNode node9 = new TreeNode(9, 7, "三级节点1"); TreeNode node10 = new TreeNode(10, 8, "三级节点2"); List<TreeNode> nodes = Arrays.asList(node1,node2,node3,node4,node5,node6,node7,node8,node9,node10); //将list转为map,以pid为key组装子节点集合 Map<Integer, Set<TreeNode>> childrenNodeMap = nodes.stream().collect(Collectors.groupingBy(TreeNode::getPid, Collectors.toSet())); //当前节点id Deque<Integer> nodeDeque = new ArrayDeque<>(); //将待搜索节点ID放入队列 nodeDeque.add(3); Integer currentNodeId; Set<Integer> resultList = new HashSet<>(); while ((currentNodeId = nodeDeque.pollFirst()) != null) { resultList.add(currentNodeId); Set<TreeNode> treeNodes = childrenNodeMap.get(currentNodeId); if (CollectionUtils.isNotEmpty(treeNodes)) { Set<Integer> childIdSet = treeNodes.stream().map(TreeNode::getId).collect(Collectors.toSet()); resultList.addAll(childIdSet); nodeDeque.addAll(childIdSet); } } System.out.println(resultList); } } /** * 节点类 * * @author Wangyangyang */ @JsonInclude(JsonInclude.Include.NON_EMPTY) class TreeNode { /** * 当前节点id */ private Integer id; /** * 父节点id */ private Integer pid; /** * 节点名称 */ private String name; public TreeNode(int id, int pid, String name) { this.id = id; this.pid = pid; this.name = name; } public TreeNode() { } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public Integer getPid() { return pid; } public void setPid(Integer pid) { this.pid = pid; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; TreeNode treeNode = (TreeNode) o; return Objects.equals(id, treeNode.id) && Objects.equals(pid, treeNode.pid) && Objects.equals(name, treeNode.name); } @Override public int hashCode() { return Objects.hash(id, pid, name); } @Override public String toString() { return "Node{" + "id=" + id + ", pid=" + pid + '}'; } }
test1测试结果:
{ "0": [ { "id": 2, "pid": 1, "name": "二级节点1" }, { "id": 7, "pid": 5, "name": "二级节点1" }, { "id": 1, "pid": 0, "name": "根节点1" }, { "id": 3, "pid": 1, "name": "二级节点2" }, { "id": 8, "pid": 6, "name": "二级节点2" }, { "id": 5, "pid": 3, "name": "三级节点2" }, { "id": 6, "pid": 3, "name": "根节点2" }, { "id": 10, "pid": 8, "name": "三级节点2" }, { "id": 4, "pid": 2, "name": "三级节点1" }, { "id": 9, "pid": 7, "name": "三级节点1" } ], "1": [ { "id": 2, "pid": 1, "name": "二级节点1" }, { "id": 7, "pid": 5, "name": "二级节点1" }, { "id": 3, "pid": 1, "name": "二级节点2" }, { "id": 8, "pid": 6, "name": "二级节点2" }, { "id": 5, "pid": 3, "name": "三级节点2" }, { "id": 6, "pid": 3, "name": "根节点2" }, { "id": 10, "pid": 8, "name": "三级节点2" }, { "id": 4, "pid": 2, "name": "三级节点1" }, { "id": 9, "pid": 7, "name": "三级节点1" } ], "2": [ { "id": 4, "pid": 2, "name": "三级节点1" } ], "3": [ { "id": 7, "pid": 5, "name": "二级节点1" }, { "id": 8, "pid": 6, "name": "二级节点2" }, { "id": 5, "pid": 3, "name": "三级节点2" }, { "id": 6, "pid": 3, "name": "根节点2" }, { "id": 10, "pid": 8, "name": "三级节点2" }, { "id": 9, "pid": 7, "name": "三级节点1" } ], "5": [ { "id": 7, "pid": 5, "name": "二级节点1" }, { "id": 9, "pid": 7, "name": "三级节点1" } ], "6": [ { "id": 8, "pid": 6, "name": "二级节点2" }, { "id": 10, "pid": 8, "name": "三级节点2" } ], "7": [ { "id": 9, "pid": 7, "name": "三级节点1" } ], "8": [ { "id": 10, "pid": 8, "name": "三级节点2" } ] }
test2测试结果:
[3, 5, 6, 7, 8, 9, 10]