TreeNode

一、场景

树结构

比如一级部门,二级部门,三级部门......形成一个树结构全部返回

二、代码

1.ITreeNode

public interface ITreeNode<T, S extends ITreeNode<T, S>> {
    /**
     * 获取节点id
     *
     * @return
     */
    T id();

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

    /**
     * 数量
     *
     * @return {@link Long}
     */
    default Long count() {
        return 0L;
    }

    /**
     * 设置数量
     */
    default void setCount(Long count) {
    }

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

    /**
     * 设置节点的子节点列表
     *
     * @param children
     */
    void setChildrenNodes(List<S> children);

    /**
     * 获取所有子节点
     *
     * @return
     */
    Iterable<S> getChildrenNodes();


}

2.TreeNodeUtils

@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class TreeNodeUtils {

    public static <S, T extends ITreeNode<S, T>> List<T> generateTrees(List<T> nodes) {
        return generateTrees(nodes, Boolean.FALSE);
    }

    public static <S, T extends ITreeNode<S, T>> List<T> generateTrees(List<T> nodes, boolean filterZeroCount) {
        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, filterZeroCount));
        return roots;
    }

    /**
     * 遍历所有节点,提供回调函数
     *
     * @param nodes 节点
     * @param node  节点
     */
    public static <S, T extends ITreeNode<S, T>> void traversalAllNode(Iterable<T> nodes, Consumer<T> node) {
        nodes.forEach(n -> {
                    node.accept(n);
                    Iterable<T> childrenNodes = n.getChildrenNodes();
                    if (Objects.nonNull(childrenNodes)) {
                        boolean hasNext = childrenNodes.iterator().hasNext();
                        if (hasNext) {
                            traversalAllNode(childrenNodes, node);
                        }
                    }
                }
        );
    }


    public static <S, T extends ITreeNode<S, T>> void setChildren(T parent, List<T> nodes, boolean filterZeroCount) {
        List<T> children = new ArrayList<>();
        Object parentId = parent.id();
        for (Iterator<T> ite = nodes.iterator(); ite.hasNext(); ) {
            T node = ite.next();
            if (Objects.isNull(node)) {
                ite.remove();
                continue;
            }
            if (Objects.equals(node.parentId(), parentId)) {
                children.add(node);
                // 从所有节点列表中删除该节点,以免后续重复遍历该节点
                ite.remove();
            }
        }

        // 如果孩子为空,则直接返回,否则继续递归设置孩子的孩子
        if (children.isEmpty()) {
            return;
        }

        children.forEach(m -> {
            // 递归设置子节点
            setChildren(m, nodes, filterZeroCount);
        });


        if (!CollectionUtils.isEmpty(children) && filterZeroCount) {
            children.removeIf(zeroCntChild -> zeroCntChild.count() == 0);
        }
        parent.setChildrenNodes(children);
        long sum = children.stream().map(T::count).mapToLong(value -> Objects.isNull(value) ? 0L : value).sum();
        parent.setCount(sum);

    }

    public static <S, T extends ITreeNode<S, T>> List<T> getLeaves(T parent) {
        List<T> leaves = new ArrayList<>();
        fillLeaves(parent, leaves);
        return leaves;
    }

    /**
     * 将parent的所有叶子节点填充至leafs列表中
     *
     * @param parent 父节点
     * @param leaves 叶子节点列表
     * @param <T>    实际节点类型
     */
    public static <S, T extends ITreeNode<S, T>> void fillLeaves(T parent, List<T> leaves) {
        List<T> childrenNodes = (List<T>) parent.getChildrenNodes();
        // 如果节点没有子节点则说明为叶子节点
        if (CollectionUtils.isEmpty(childrenNodes)) {
            leaves.add(parent);
            return;
        }
        // 递归调用子节点,查找叶子节点
        for (T childrenNode : childrenNodes) {
            fillLeaves(childrenNode, leaves);
        }
    }

    /**
     * 过滤树
     * @param trees
     * @param filterNodes
     * @param <S>
     * @param <T>
     * @return
     */
    public static <S, T extends ITreeNode<S, T>> List<T> filterTrees(List<T> trees, List<S> filterNodes) {
        List<T> filterTrees = new ArrayList<>();
        for (S filterNode : filterNodes) {
            // 通过克隆对象清除过滤点后层级,不动原对象,防止过滤点有层级关系
            List<T> canBeModifiedTrees = new ArrayList<>(trees);
            T filterTree = filterPoint(filterNode, canBeModifiedTrees);
            if (!Objects.isNull(filterTree)) {
                filterTrees.add(filterTree);
            }
        }
        return filterTrees;
    }

    /**
     * 过滤节点
     */
    public static <S, T extends ITreeNode<S, T>> T filterPoint(S filterNode, List<T> childrenTrees) {
        if(!CollectionUtils.isEmpty(childrenTrees)) {
            for (ListIterator<T> iterator = childrenTrees.listIterator(); iterator.hasNext();) {
                T node = iterator.next();
                Object id = node.id();
                T canBeModifiedNode = node.clone(node);
                // 找到过滤点
                if (id.equals(filterNode)) {
                    canBeModifiedNode.setChildrenNodes(new ArrayList<>());
                    return canBeModifiedNode;
                }
                if (node.getChildrenNodes() != null) {
                    List<T> childrenNodes = Lists.newArrayList((node.getChildrenNodes()));
                    // 过滤点向下递归
                    T findNode = filterPoint(filterNode, childrenNodes);
                    if (!Objects.isNull(findNode)) {
                        canBeModifiedNode.setChildrenNodes(Arrays.asList(findNode));
                        return canBeModifiedNode;
                    }
                }
            }
        }
        return null;
    }
}

3.DepartmentTreeNode

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Schema
public class DepartmentTreeNode implements ITreeNode<Integer, MarsDepartmentTreeNode> {
    @Schema(title = "部门ID", example = "10")
    private Integer departmentId;

    @Schema(title = "部门名", example = "产品研发中心")
    private String departmentName;

    @Schema(title = "部门父ID", example = "1")
    private Integer parentDepartmentId;

    @Schema(title = "子节点")
    private List<MarsDepartmentTreeNode> childrenNodes;

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

    @Override
    public Integer parentId() {
        return this.parentDepartmentId;
    }

    @Override
    public boolean root() {
        return Objects.equals(-1, this.parentDepartmentId);
    }

    @Override
    public void setChildrenNodes(List<MarsDepartmentTreeNode> childrenNodes) {
        this.childrenNodes = childrenNodes;
    }

    
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值