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]