From 409ddcbf811c7f7ca3fcc376d1b61b75dc9230e4 Mon Sep 17 00:00:00 2001 From: b2baccline <23131013+b2baccline@users.noreply.github.com> Date: Sun, 21 Jun 2020 20:16:28 +0800 Subject: [PATCH] =?UTF-8?q?:sparkles:=20TreeUtil=20+=20TreeNode=20?= =?UTF-8?q?=E7=94=A8=E4=BA=8E=E9=80=9A=E7=94=A8=E6=A0=91=E5=BD=A2=E7=BB=93?= =?UTF-8?q?=E6=9E=84=E6=9E=84=E9=80=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/core/tree/SimpleTreeNode.java | 26 ++++ .../ballcat/common/core/tree/TreeNode.java | 38 ++++++ .../ballcat/common/core/util/TreeUtil.java | 125 ++++++++++++++++++ 3 files changed, 189 insertions(+) create mode 100644 ballcat-common/ballcat-common-core/src/main/java/com/hccake/ballcat/common/core/tree/SimpleTreeNode.java create mode 100644 ballcat-common/ballcat-common-core/src/main/java/com/hccake/ballcat/common/core/tree/TreeNode.java create mode 100644 ballcat-common/ballcat-common-core/src/main/java/com/hccake/ballcat/common/core/util/TreeUtil.java diff --git a/ballcat-common/ballcat-common-core/src/main/java/com/hccake/ballcat/common/core/tree/SimpleTreeNode.java b/ballcat-common/ballcat-common-core/src/main/java/com/hccake/ballcat/common/core/tree/SimpleTreeNode.java new file mode 100644 index 00000000..6a7f5513 --- /dev/null +++ b/ballcat-common/ballcat-common-core/src/main/java/com/hccake/ballcat/common/core/tree/SimpleTreeNode.java @@ -0,0 +1,26 @@ +package com.hccake.ballcat.common.core.tree; + +import lombok.Data; + +import java.util.List; + +/** + * @author Hccake + * @version 1.0 + * @date 2020/6/21 17:08 + */ +@Data +public class SimpleTreeNode implements TreeNode{ + /** + * 节点ID + */ + private T id; + /** + * 父节点ID + */ + private T parentId; + /** + * 子节点集合 + */ + private List> children; +} diff --git a/ballcat-common/ballcat-common-core/src/main/java/com/hccake/ballcat/common/core/tree/TreeNode.java b/ballcat-common/ballcat-common-core/src/main/java/com/hccake/ballcat/common/core/tree/TreeNode.java new file mode 100644 index 00000000..5542e1e3 --- /dev/null +++ b/ballcat-common/ballcat-common-core/src/main/java/com/hccake/ballcat/common/core/tree/TreeNode.java @@ -0,0 +1,38 @@ +package com.hccake.ballcat.common.core.tree; + +import java.util.List; + +/** + * @author Hccake + * @version 1.0 + * @date 2020/6/21 17:05 + */ +public interface TreeNode { + /** + * 获取节点id + * + * @return 树节点id + */ + T getId(); + + /** + * 获取该节点的父节点id + * + * @return 父节点id + */ + T getParentId(); + + /** + * 设置节点的子节点列表 + * + * @param children 子节点 + */ + void setChildren(List> children); + + /** + * 获取所有子节点 + * + * @return 子节点列表 + */ + List> getChildren(); +} diff --git a/ballcat-common/ballcat-common-core/src/main/java/com/hccake/ballcat/common/core/util/TreeUtil.java b/ballcat-common/ballcat-common-core/src/main/java/com/hccake/ballcat/common/core/util/TreeUtil.java new file mode 100644 index 00000000..9586acfc --- /dev/null +++ b/ballcat-common/ballcat-common-core/src/main/java/com/hccake/ballcat/common/core/util/TreeUtil.java @@ -0,0 +1,125 @@ +package com.hccake.ballcat.common.core.util; + +import com.hccake.ballcat.common.core.tree.TreeNode; +import lombok.experimental.UtilityClass; +import org.springframework.util.CollectionUtils; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Objects; +import java.util.function.Function; + +/** + * @author Hccake + * @version 1.0 + * @date 2020/6/21 17:21 + */ +@UtilityClass +public class TreeUtil { + + /** + * 根据一个TreeNode集合,返回构建好的树列表 + * @param nodes TreeNode集合 + * @param rootId 根节点Id + * @param TreeNode的子类 + * @param TreeNodeId的类型 + * @return 树列表 + */ + public , I> List buildTree(List nodes, I rootId) { + return TreeUtil.buildTree(nodes, rootId, Function.identity()); + } + + /** + * 根据源数据列表转换为树 + * @param list 源数据列表 + * @param rootId 根节点Id + * @param convertToTree 转换方法 + * @param TreeNode的子类 + * @param TreeNodeId的类型 + * @param 源数据类型 + * @return 树列表 + */ + public , I, R> List buildTree(List list, I rootId, Function convertToTree) { + + List roots = new ArrayList<>(); + for (Iterator ite = list.iterator(); ite.hasNext(); ) { + T node = convertToTree.apply(ite.next()); + if (Objects.equals(rootId, node.getParentId())) { + roots.add(node); + ite.remove(); + } + } + + roots.forEach(r -> { + TreeUtil.setChildren(r, list, convertToTree); + }); + return roots; + } + + + /** + * 从所有节点列表中查找并设置parent的所有子节点 + * + * @param parent 父节点 + * @param nodes 所有树节点列表 + */ + public , I, R> void setChildren(T parent, List nodes, Function convertToTree) { + List children = new ArrayList<>(); + Object parentId = parent.getId(); + for (Iterator ite = nodes.iterator(); ite.hasNext(); ) { + T node = convertToTree.apply(ite.next()); + if (Objects.equals(node.getParentId(), parentId)) { + children.add(node); + ite.remove(); + } + } + + // 如果孩子为空,则直接返回,否则继续递归设置孩子的孩子 + if (children.isEmpty()) { + return; + } + parent.setChildren(children); + children.forEach(m -> { + // 递归设置子节点 + setChildren(m, nodes, convertToTree); + }); + } + + + /** + * 获取指定树节点下的所有叶子节点 + * + * @param parent 父节点 + * @param 实际节点类型 + * @return 叶子节点 + */ + public > List getLeafs(T parent) { + List leafs = new ArrayList<>(); + fillLeaf(parent, leafs); + return leafs; + } + + /** + * 将parent的所有叶子节点填充至leafs列表中 + * + * @param parent 父节点 + * @param leafs 叶子节点列表 + * @param 实际节点类型 + */ + @SuppressWarnings("rawtypes, unchecked") + public void fillLeaf(T parent, List leafs) { + List children = parent.getChildren(); + // 如果节点没有子节点则说明为叶子节点 + if (CollectionUtils.isEmpty(children)) { + leafs.add(parent); + return; + } + // 递归调用子节点,查找叶子节点 + for (T child : children) { + fillLeaf(child, leafs); + } + } + + +}