从叶子节点反向构建树 java

        在构建树时,某些特殊的业务场景下,我们需要从叶子节点向根节点反向构建树,方法如下:

        新建数据源对象DataSourcce,一般为从数据库查询到的数据

package bean;

import lombok.Data;

import java.io.Serializable;

@Data
public class DataSource implements Serializable {

    private static final long serialVersionUID = 6485359623656969131L;

    private Long id;

    private String name;

    /**
     * 父节点id
     */
    private Long parentId;

    /**
     * 是否为叶子节点
     */
    private Boolean isLeaf;

}

        新建树对象TreeNode,即需要返回的树节点对象

package bean;

import lombok.Data;

import java.util.List;

@Data
public class TreeNode {
    private Long id;

    private String value;

    private String label;

    private Long parentId;

    private Boolean isLeaf;

    private List<TreeNode> children;
}

核心方法buildDataSourceTree

/**
     * 从叶子节点构建树
     *
     * @param orgs 叶子节点集合
     * @param parentTree 最终的树
     * @return
     */
    private List<TreeNode> buildDataSourceTree(List<DataSource> orgs, List<TreeNode> parentTree) {
        // 最终树
        if (CollectionUtils.isNotEmpty(orgs)) {
            // 叶子节点的父节点集合
            List<DataSource> parrentOrgsList = new ArrayList<>();
            // 根据父节点id分组,便于分批处理减少循环次数 key:父节点id value:此父节点的子节点集合
            Map<Long, List<DataSource>> orgMap = orgs.stream().collect(Collectors.groupingBy(DataSource::getParentId));
            // copy最终树
            final List<TreeNode> finalParentTree = parentTree;
            // 是否还有节点未回溯到根节点
            AtomicReference<Boolean> isAllRootNode = new AtomicReference<>(false);
            // 循环orgMap分批处理
            orgMap.forEach((key, value) -> {
                // 若父节点id=1,则说明已经到达根节点
                if (key == 1L) {
                    return;
                }
                isAllRootNode.set(true);
                // 查询父节点
                Wrapper<DataSource> parentNodeWrapper = Wrappers.<DataSource>lambdaQuery()
                        .eq(DataSource::getId, key);
                DataSource parentOrgs = super.getOne(parentNodeWrapper);
                parrentOrgsList.add(parentOrgs);
                // 判断父节点是否在树中已存在(只回溯了一层)
                for (int i = 0; i < finalParentTree.size(); i++) {
                    // 如果存在,直接将子树添加到该节点下
                    if (finalParentTree.get(i).getId().equals(parentOrgs.getId())) {
                        if (value.get(0).getIsLeaf()) {
                            finalParentTree.get(i).getChildren().addAll(
                                    Objects.requireNonNull(transToTreeNode(value)));
                        }
                        finalParentTree.get(i).getChildren().addAll(getChlidenNode(finalParentTree, key));
                        return;
                    }
                }
                // 在树中不存在,则新建一个节点
                TreeNode node = Objects.requireNonNull(transToTreeNode(new ArrayList<DataSource>() {
                    private static final long serialVersionUID = -8635887848543228675L;

                    {
                        add(parentOrgs);
                    }
                })).get(0);

                // 构建此层父节点的树,并将父节点的子节点添加到对于父节点下
                List<TreeNode> treeNodeVOS = new ArrayList<>();
                // 如果是叶子节点,将节点添加进去
                if (value.get(0).getIsLeaf()) {
                    treeNodeVOS.addAll(Objects.requireNonNull(transToTreeNode(value)));
                }
                // 将子树添加进去
                treeNodeVOS.addAll(getChlidenNode(finalParentTree, key));

                node.setChildren(treeNodeVOS);
                finalParentTree.add(node);
            });

            // 如果还有节点未回溯到根节点,进入循环构建
            if (isAllRootNode.get()) {
                buildDataSourceTree(parrentOrgsList, finalParentTree);
            }
            // 赋值到最终树
            parentTree = finalParentTree;
        }
        return parentTree;
    }

    /**
     * 获取子树
     *
     * @param parentTree
     * @param parentId
     * @return
     */
    private List<TreeNode> getChlidenNode(List<TreeNode> parentTree, Long parentId) {
        List<TreeNode> childen = new ArrayList<>();
        for (int i = 0; i < parentTree.size(); i++) {
            if (parentId.equals(parentTree.get(i).getParentId())) {
                childen.add(parentTree.get(i));
            }
        }
        // 获取子树的同时,将子树从最终树删除
        parentTree.removeAll(childen);
        return childen;
    }

    /**
     * 转换DataSource为TreeNode
     *
     * @param list
     * @return
     */
    private List<TreeNode> transToTreeNode(List<DataSource> list) {
        if (CollectionUtils.isEmpty(list)) {
            return null;
        }
        List<TreeNode> tree = new ArrayList<>();
        list.forEach(org -> {
            TreeNode vo = new TreeNode();
            vo.setId(org.getId());
            vo.setValue(String.valueOf(org.getId()));
            vo.setLabel(org.getName());
            vo.setIsLeaf(org.getIsLeaf());
            vo.setParentId(org.getParentId());
            tree.add(vo);
        });
        return tree;
    }

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值