侧边栏壁纸
博主头像
MULY博主等级

大直若屈,大巧若拙,大辩若讷

  • 累计撰写 11 篇文章
  • 累计创建 20 个标签
  • 累计收到 1 条评论

Java之TreeUtils生成一切对象树形结构

MULY
2022-03-10 / 0 评论 / 1 点赞 / 154 阅读 / 3,441 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2022-03-10,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

TreeNode用来表示每个树节点的抽象,即需要生成树的对象需要实现此接口。

public interface TreeNode<T> {

    /**
     * 获取节点id
     *
     * @return 树节点id
     */
    T id();

    /**
     * 获取该节点的父节点id
     *
     * @return 父节点id
     */
    T parentId();

    /**
     * 是否是根节点
     *
     * @return true:根节点
     */
    boolean root();

    /**
     * 设置节点的子节点列表
     *
     * @param children 子节点
     */
    void setChildren(List<? extends TreeNode<T>> children);

    /**
     * 获取所有子节点
     *
     * @return 子节点列表
     */
    List<? extends TreeNode<T>> getChildren();
}

TreeUtils用来生成树形结构,以及获取所有叶子节点等操作

public class TreeUtils {

    /**
     * 根据所有树节点列表,生成含有所有树形结构的列表
     *
     * @param nodes 树形节点列表
     * @param <T>   节点类型
     * @return 树形结构列表
     */
    public static <T extends TreeNode<?>> List<T> generateTrees(List<T> nodes) {
        List<T> roots = new ArrayList<>();
        for (Iterator<T> ite = nodes.iterator(); ite.hasNext(); ) {
            T node = ite.next();
            if (node.root()) {
                roots.add(node);
                // 从所有节点列表中删除该节点,以免后续重复遍历该节点
                ite.remove();
            }
        }
        roots.forEach(r -> setChildren(r, nodes));
        return roots;
    }

    /**
     * 从所有节点列表中查找并设置parent的所有子节点
     *
     * @param parent 父节点
     * @param nodes  所有树节点列表
     */
    @SuppressWarnings("all")
    public static <T extends TreeNode> void setChildren(T parent, List<T> nodes) {
        List<T> children = new ArrayList<>();
        Object parentId = parent.id();
        for (Iterator<T> ite = nodes.iterator(); ite.hasNext(); ) {
            T node = ite.next();
            if (Objects.equals(node.parentId(), parentId)) {
                children.add(node);
                // 从所有节点列表中删除该节点,以免后续重复遍历该节点
                ite.remove();
            }
        }
        // 如果孩子为空,则直接返回,否则继续递归设置孩子的孩子
        if (children.isEmpty()) {
            return;
        }
        parent.setChildren(children);
        children.forEach(m -> {
            // 递归设置子节点
            setChildren(m, nodes);
        });
    }

    /**
     * 获取指定树节点下的所有叶子节点
     *
     * @param parent 父节点
     * @param <T>    实际节点类型
     * @return 叶子节点
     */
    public static <T extends TreeNode<?>> List<T> getLeafs(T parent) {
        List<T> leafs = new ArrayList<>();
        fillLeaf(parent, leafs);
        return leafs;
    }

    /**
     * 将parent的所有叶子节点填充至leafs列表中
     *
     * @param parent 父节点
     * @param leafs  叶子节点列表
     * @param <T>    实际节点类型
     */
    @SuppressWarnings("all")
    public static <T extends TreeNode> void fillLeaf(T parent, List<T> leafs) {
        List<T> children = parent.getChildren();
        // 如果节点没有子节点则说明为叶子节点
        if (children == null || children.isEmpty()) {
            leafs.add(parent);
            return;
        }
        // 递归调用子节点,查找叶子节点
        for (T child : children) {
            fillLeaf(child, leafs);
        }
    }


}

构建自己的dto

@Data
@NoArgsConstructor
public class MenuVo implements TreeNode<Long>{

    private Long id;

    private Long pid;

    private Integer type;

    private String name;

    private String icon;

    private String code;

    private Integer status;

    private List<MenuVo> children;

    @Override
    public Long id() {
        return this.id;
    }

    @Override
    public Long parentId() {
        return this.pid;
    }

    @Override
    public boolean root() {
        return Objects.equals(this.pid, 0L);
    }

    @Override
    public void setChildren(List children) {
        this.children = children;
    }

    public MenuVo(Long id, String name, Long pid) {
        this.id = id;
        this.pid = pid;
        this.name = name;
    }


    public MenuVo(Long id, Long pid, Integer type, String name, String icon, String code, Integer status, List<MenuVo> children) {
        this.id = id;
        this.pid = pid;
        this.type = type;
        this.name = name;
        this.icon = icon;
        this.code = code;
        this.status = status;
        this.children = children;
    }
}

测试类

public class MenoTest {


    public static void main(String[] args) {

        List<MenuVo> menuList = new ArrayList<>();
        menuList.add(new MenuVo(1L, "根节点", 0L));
        menuList.add(new MenuVo(2L, "第二层级节点2", 1L));
        menuList.add(new MenuVo(3L, "第二层级节点3", 1L));
        menuList.add(new MenuVo(4L, "第三层级节点4", 2L));
        menuList.add(new MenuVo(5L, "第三层级节点5", 2L));
        menuList.add(new MenuVo(6L, "第四层级节点6", 4L));
        menuList.add(new MenuVo(7L, "第四层级节点7", 5L));
        menuList.add(new MenuVo(8L, "第五层级节点8", 7L));

        List<MenuVo> menuVos = TreeUtils.generateTrees(menuList);

        System.out.println(JSONUtil.toJsonPrettyStr(menuVos));
    }

}

结果如下

image.png

1

评论区