✨ TreeUtil + TreeNode 用于通用树形结构构造
This commit is contained in:
@@ -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<T> implements TreeNode<T>{
|
||||||
|
/**
|
||||||
|
* 节点ID
|
||||||
|
*/
|
||||||
|
private T id;
|
||||||
|
/**
|
||||||
|
* 父节点ID
|
||||||
|
*/
|
||||||
|
private T parentId;
|
||||||
|
/**
|
||||||
|
* 子节点集合
|
||||||
|
*/
|
||||||
|
private List<? extends TreeNode<T>> children;
|
||||||
|
}
|
||||||
@@ -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<T> {
|
||||||
|
/**
|
||||||
|
* 获取节点id
|
||||||
|
*
|
||||||
|
* @return 树节点id
|
||||||
|
*/
|
||||||
|
T getId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取该节点的父节点id
|
||||||
|
*
|
||||||
|
* @return 父节点id
|
||||||
|
*/
|
||||||
|
T getParentId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置节点的子节点列表
|
||||||
|
*
|
||||||
|
* @param children 子节点
|
||||||
|
*/
|
||||||
|
void setChildren(List<? extends TreeNode<T>> children);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有子节点
|
||||||
|
*
|
||||||
|
* @return 子节点列表
|
||||||
|
*/
|
||||||
|
List<? extends TreeNode<T>> getChildren();
|
||||||
|
}
|
||||||
@@ -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 <T> TreeNode的子类
|
||||||
|
* @param <I> TreeNodeId的类型
|
||||||
|
* @return 树列表
|
||||||
|
*/
|
||||||
|
public <T extends TreeNode<I>, I> List<T> buildTree(List<T> nodes, I rootId) {
|
||||||
|
return TreeUtil.buildTree(nodes, rootId, Function.identity());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据源数据列表转换为树
|
||||||
|
* @param list 源数据列表
|
||||||
|
* @param rootId 根节点Id
|
||||||
|
* @param convertToTree 转换方法
|
||||||
|
* @param <T> TreeNode的子类
|
||||||
|
* @param <I> TreeNodeId的类型
|
||||||
|
* @param <R> 源数据类型
|
||||||
|
* @return 树列表
|
||||||
|
*/
|
||||||
|
public <T extends TreeNode<I>, I, R> List<T> buildTree(List<R> list, I rootId, Function<R, T> convertToTree) {
|
||||||
|
|
||||||
|
List<T> roots = new ArrayList<>();
|
||||||
|
for (Iterator<R> 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 <T extends TreeNode<I>, I, R> void setChildren(T parent, List<R> nodes, Function<R, T> convertToTree) {
|
||||||
|
List<T> children = new ArrayList<>();
|
||||||
|
Object parentId = parent.getId();
|
||||||
|
for (Iterator<R> 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 <T> 实际节点类型
|
||||||
|
* @return 叶子节点
|
||||||
|
*/
|
||||||
|
public <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("rawtypes, unchecked")
|
||||||
|
public <T extends TreeNode> void fillLeaf(T parent, List<T> leafs) {
|
||||||
|
List<T> children = parent.getChildren();
|
||||||
|
// 如果节点没有子节点则说明为叶子节点
|
||||||
|
if (CollectionUtils.isEmpty(children)) {
|
||||||
|
leafs.add(parent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 递归调用子节点,查找叶子节点
|
||||||
|
for (T child : children) {
|
||||||
|
fillLeaf(child, leafs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user