前言
很久不写业务接口, 最近刚好遇到需要实现树结构, 做下简单总结
逻辑实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
| package com.easyliao.demo;
import com.fasterxml.jackson.databind.ObjectMapper; import lombok.Data;
import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.stream.Collectors;
public class TreeTest {
@Data public static class Node { private Integer id; private String name; private Integer pid; private List<Node> children;
public Node(Integer id, String name, Integer pid) { this.id = id; this.name = name; this.pid = pid; } }
public static void main(String[] args) throws Exception{ Node p0 = new Node(1, "p00", 0); Node p1 = new Node(2, "p01", 0); Node p2 = new Node(3, "p10", 1); Node p3 = new Node(4, "p11", 1); Node p4 = new Node(5, "p20", 3); List<Node> nodes = Arrays.asList(p0, p1, p2, p3, p4); List<Node> tree = buildTree(nodes);
ObjectMapper objectMapper = new ObjectMapper(); System.out.println(objectMapper.writeValueAsString(tree));
}
public Node buildOneNodeTree(List<Node> pidList){ Map<Integer,List<Node>> pidListMap = pidList.stream().collect(Collectors.groupingBy(Node::getPid)); pidList.forEach(item->item.setChildren(pidListMap.get(item.getId()))); return pidListMap.get(0).get(0); }
public static List<Node> buildTree(List<Node> pidList){ Map<Integer,List<Node>> pidListMap = pidList.stream().collect(Collectors.groupingBy(Node::getPid)); pidList.forEach(item->item.setChildren(pidListMap.get(item.getId()))); return pidListMap.get(0); }
}
|
简单抽象
我们这里做一个简单工具类
- 首先我们抽象一个接口, 所有实现Tree结构的对象需要实现该接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| package cn.idea360.assistant.dev.tree;
import java.util.List;
public interface TreeNode<T extends TreeNode<T, ID>, ID> {
ID getId();
ID getPid();
List<T> getChildren();
void setChildren(List<T> children);
}
|
- 定义基本实现类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| package cn.idea360.assistant.dev.tree;
import lombok.Data;
import java.util.ArrayList; import java.util.List;
@Data public class Node implements TreeNode<Node, Long> {
private Long id;
private Long pid;
private transient List<Node> children = new ArrayList<>();
public Node(Long id, Long pid) { this.id = id; this.pid = pid; }
}
|
- 工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
| package cn.idea360.assistant.dev.tree;
import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors;
public class TreeBuilder {
private TreeBuilder() { }
public static <T extends TreeNode<T, ID>, ID> List<T> buildTree(List<T> nodes) { return new ArrayList<>(buildTreeMap(nodes).values()); }
public static <T extends TreeNode<T, ID>, ID> Map<ID, T> buildTreeMap(List<T> nodes) { Map<ID, T> nodeMap = new HashMap<>(); Map<ID, T> roots = new HashMap<>();
for (T node : nodes) { nodeMap.put(node.getId(), node); }
for (T node : nodes) { ID pid = node.getPid(); if (pid == null || nodeMap.get(pid) == null) { roots.put(node.getId(), node); } else { T parent = nodeMap.get(pid); if (parent != null) { parent.getChildren().add(node); } } }
return roots; }
public static <T extends TreeNode<T, ID>, ID> List<T> getTreeNodes(List<T> nodes, ID pid) { Map<ID, List<T>> pidMap = nodes.stream().collect(Collectors.groupingBy(TreeNode::getPid)); nodes.forEach(node -> node.setChildren(pidMap.get(node.getId()))); return pidMap.get(pid); }
public static <T extends TreeNode<T, ID>, ID> List<T> getParentNodes(List<T> nodes, ID id) { List<T> result = new ArrayList<>(); Map<ID, T> nodeMap = nodes.stream().collect(Collectors.toMap(TreeNode::getId, Function.identity())); T current = nodeMap.get(id); while (current != null) { result.add(current); current = nodeMap.get(current.getPid()); } Collections.reverse(result); return result; } }
|
- 测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| public class TreeTest {
private final ObjectMapper objectMapper = new ObjectMapper();
private final List<Node> nodes = new ArrayList<>();
@Before public void init() { nodes.add(new Node(1L, 0L)); nodes.add(new Node(2L, 1L)); nodes.add(new Node(3L, 1L)); nodes.add(new Node(4L, 2L)); nodes.add(new Node(5L, 3L)); }
@SneakyThrows @Test public void t1() { List<Node> tree = buildTree(nodes); System.out.println("tree结构:\n" + objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(tree)); }
@SneakyThrows @Test public void t2() { List<Node> parentNodes = getParentNodes(nodes, 5L); System.out.println("节点链路:\n" + objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(parentNodes)); }
@SneakyThrows @Test public void t3() { List<Node> treeNodes = getTreeNodes(nodes, 2L); System.out.println("叶子节点:\n" + objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(treeNodes)); } }
|
输出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| tree结构: [ { "id" : 1, "pid" : 0, "children" : [ { "id" : 2, "pid" : 1, "children" : [ { "id" : 4, "pid" : 2, "children" : [ ] } ] }, { "id" : 3, "pid" : 1, "children" : [ { "id" : 5, "pid" : 3, "children" : [ ] } ] } ] } ] 节点链路: [ { "id" : 1, "pid" : 0, "children" : [ ] }, { "id" : 3, "pid" : 1, "children" : [ ] }, { "id" : 5, "pid" : 3, "children" : [ ] } ] 叶子节点: [ { "id" : 4, "pid" : 2, "children" : null } ]
|
最后
欢迎大家关注公众号【当我遇上你】支持我。