1. 背景
该工具类主要用来处理树形结构业务。怎么在数据库里面存储树形结构? 拿公司里面的人员来说
@Data
public class People {
private Long id;
private Long pId;
private String name;
private Integer rank = 0;
private List<People> subMenus = new ArrayList<>();
public static People of(Long id, Long pId, int rank, String name) {
People people = new People();
people.setId(id);
people.setPId(pId);
people.setRank(rank);
people.setName(name);
return people;
}
}
一个节点应该有自己的孩子节点,和 父亲节点的id。
2. 使用
public static void main(String[] args) {
People people1 = People.of(0L, -1L, 1, "老板");
People people2 = People.of(1L, 0L, 2, "经理1");
People people3 = People.of(2L, 0L, 1, "经理2");
People people4 = People.of(3L, 1L, 2, "项目经理1");
People people5 = People.of(4L, 1L, 1, "项目经理2");
People people6 = People.of(5L, 2L, 2, "项目经理3");
People people7 = People.of(6L, 2L, 1, "项目经理4");
People people8 = People.of(7L, 3L, 2, "普工1");
People people9 = People.of(8L, 3L, 1, "普工2");
List<People> peoples = asList(people1, people2, people3, people4, people5, people6, people7, people8, people9);
List<People> treePeople = TreeUtils.buildTree(
peoples,
people -> people.getPId().equals(-1L),
(parent, node) -> Objects.equals(parent.getId(), node.getPId()),
People::setSubMenus
);
// 先序遍历
System.out.println("先序遍历========");
TreeUtils.preOrder(treePeople, (people -> System.out.println(people.getName())), People::getSubMenus);
// 层序遍历
System.out.println("层序遍历========");
TreeUtils.levelOrder(treePeople, (people -> System.out.println(people.getName())), People::getSubMenus);
// 后序遍历
System.out.println("后序遍历========");
TreeUtils.postOrder(treePeople, (people -> System.out.println(people.getName())), People::getSubMenus);
// 同一层按照rank升序
System.out.println("同层按照rank升序========");
TreeUtils.sort(treePeople, Comparator.comparingInt(People::getRank), People::getSubMenus);
TreeUtils.levelOrder(treePeople, (System.out::println), People::getSubMenus);
//先序遍历========
//老板
//经理1
//项目经理1
//普工1
//普工2
//项目经理2
//经理2
//项目经理3
//项目经理4
//层序遍历========
//老板
//经理1
//经理2
//项目经理1
//项目经理2
//项目经理3
//项目经理4
//普工1
//普工2
//后序遍历========
//普工1
//普工2
//项目经理1
//项目经理2
//经理1
//项目经理3
//项目经理4
//经理2
//老板
//同层按照rank升序========
//People(id=0, pId=-1, name=老板, rank=1, subMenus=[People(id=2, pId=0, name=经理2, rank=1, subMenus=[People(id=6, pId=2, name=项目经理4, rank=1, subMenus=[]), People(id=5, pId=2, name=项目经理3, rank=2, subMenus=[])]), People(id=1, pId=0, name=经理1, rank=2, subMenus=[People(id=4, pId=1, name=项目经理2, rank=1, subMenus=[]), People(id=3, pId=1, name=项目经理1, rank=2, subMenus=[People(id=8, pId=3, name=普工2, rank=1, subMenus=[]), People(id=7, pId=3, name=普工1, rank=2, subMenus=[])])])])
//People(id=2, pId=0, name=经理2, rank=1, subMenus=[People(id=6, pId=2, name=项目经理4, rank=1, subMenus=[]), People(id=5, pId=2, name=项目经理3, rank=2, subMenus=[])])
//People(id=1, pId=0, name=经理1, rank=2, subMenus=[People(id=4, pId=1, name=项目经理2, rank=1, subMenus=[]), People(id=3, pId=1, name=项目经理1, rank=2, subMenus=[People(id=8, pId=3, name=普工2, rank=1, subMenus=[]), People(id=7, pId=3, name=普工1, rank=2, subMenus=[])])])
//People(id=6, pId=2, name=项目经理4, rank=1, subMenus=[])
//People(id=5, pId=2, name=项目经理3, rank=2, subMenus=[])
//People(id=4, pId=1, name=项目经理2, rank=1, subMenus=[])
//People(id=3, pId=1, name=项目经理1, rank=2, subMenus=[People(id=8, pId=3, name=普工2, rank=1, subMenus=[]), People(id=7, pId=3, name=普工1, rank=2, subMenus=[])])
//People(id=8, pId=3, name=普工2, rank=1, subMenus=[])
//People(id=7, pId=3, name=普工1, rank=2, subMenus=[])
}
使用简单易懂。
3. 核心源码
package com.hdu.treeUtils;
import java.util.*;
import java.util.function.*;
import java.util.stream.Collectors;
public class TreeUtils {
public static <E> List<E> buildTree(
List<E> allNodes,
Predicate<E> rootFilter,
BiFunction<E, E, Boolean> childrenFilter,
BiConsumer<E, List<E>> setChildren) {
// 找到根节点
List<E> roots = allNodes
.stream()
.filter(rootFilter)
.collect(Collectors.toList());
// 给每个根节点设置子节点
for (E root : roots) {
setChildren.accept(
root,
getChildren(root, allNodes, childrenFilter, setChildren)
);
}
return roots;
}
private static <E> List<E> getChildren(E parent,
List<E> allData,
BiFunction<E, E, Boolean> childrenFilter,
BiConsumer<E, List<E>> setSubChildren) {
// 找出当前 parent 的所有子节点
List<E> children = allData
.stream()
.filter(data -> childrenFilter.apply(parent, data))
.collect(Collectors.toList());
// 给每个子节点设置子节点
for (E child : children) {
setSubChildren.accept(
child,
getChildren(child, allData, childrenFilter, setSubChildren)
);
}
return children;
}
public static <E> void preOrder(List<E> nodes, Consumer<E> consumer, Function<E, List<E>> getSubChildren) {
for (E node : nodes) {
consumer.accept(node);
List<E> children = getSubChildren.apply(node);
if (children != null && !children.isEmpty()) {
preOrder(children, consumer, getSubChildren);
}
}
}
public static <E> void levelOrder(List<E> nodes, Consumer<E> consumer, Function<E, List<E>> getSubChildren) {
Queue<E> queue = new LinkedList<>(nodes);
while (!queue.isEmpty()) {
E item = queue.poll();
consumer.accept(item);
List<E> childList = getSubChildren.apply(item);
if (childList != null && !childList.isEmpty()) {
queue.addAll(childList);
}
}
}
public static <E> void postOrder(List<E> nodes, Consumer<E> consumer, Function<E, List<E>> getSubChildren) {
for (E item : nodes) {
List<E> childList = getSubChildren.apply(item);
if (childList != null && !childList.isEmpty()) {
postOrder(childList, consumer, getSubChildren);
}
consumer.accept(item);
}
}
public static <E> void sort(List<E> tree, Comparator<? super E> comparator, Function<E, List<E>> getChildren) {
for (E item : tree) {
List<E> childList = getChildren.apply(item);
if (childList != null && !childList.isEmpty()) {
sort(childList, comparator, getChildren);
}
}
tree.sort(comparator);
}
}