树型工具类封装

271 阅读3分钟

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);
    }


}

4. 源码

TreeUtils: TreeUtils (gitee.com)