package com.demo;
import org.springframework.util.CollectionUtils;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* 文件名:TreeUtil
* 创建者:
* 创建时间:2024-06-29
* 描述:
*/
public class TreeUtil {
/**
* 因为是工具类所以私有化此类构造
*/
private TreeUtil(){}
/**
* 通过递归方式构建树
* @param list
* @return
* @param <T>
*/
public static <T> List<T> buildTreeByRecursion(List<T> list) {
return buildTreeByRecursion(list, "id", "parentId", "children");
}
/**
* 通过Map方式构建树
* @param list
* @return
* @param <T>
*/
public static <T> List<T> buildTreeByMap(List<T> list) {
return buildTreeByMap(list, "id", "parentId", "children", "root");
}
/**
* 通过两层for循环方式构建树
* @param list
* @return
* @param <T>
*/
public static <T> List<T> buildTreeByTwoLayersFor(List<T> list) {
return buildTreeByTwoLayersFor(list, "id", "parentId", "children", "root");
}
/**
* 递归方式构建树
* @param list
* @param idName id名称
* @param parentIdName 父id名称
* @param childrenName 子集
* @return
* @param <T>
*/
public static <T> List<T> buildTreeByRecursion(List<T> list, String idName, String parentIdName, String childrenName) {
if (CollectionUtils.isEmpty(list)) {
return Collections.emptyList();
}
List<T> returnList = new ArrayList<>();
//获取list中所有的主键id
List<String> ids = list.stream().map(o -> getFieldValue(o, idName).toString()).collect(Collectors.toList());
for (T t : list) {
String parentId = getFieldValue(t, parentIdName).toString();
//如果是顶级节点, 遍历该父节点的所有子节点,因为顶层的parentId为0
if (!ids.contains(parentId)) {
buildTreeRecursive(list, t, idName, parentIdName, childrenName);
returnList.add(t);
}
}
if (returnList.isEmpty()) {
returnList = list;
}
return returnList;
}
/**
* 递归fn
* @param list 分类表
* @param node 子节点
* @param idName
* @param parentIdName
* @param childrenName
* @param <T>
*/
private static <T> void buildTreeRecursive(List<T> list, T node, String idName, String parentIdName, String childrenName) {
// 得到子节点列表
List<T> childList = getChildList(list, node, idName, parentIdName);
setFieldValue(node, childList, childrenName);
for (T child : childList) {
if (hasChild(list, child, idName, parentIdName)) {
buildTreeRecursive(list, child, idName, parentIdName, childrenName);
}
}
}
/**
* 获取子节点列表
* @param list
* @param node
* @param idName
* @param parentIdName
* @return
* @param <T>
*/
private static <T> List<T> getChildList(List<T> list, T node, String idName, String parentIdName) {
List<T> tlist = new ArrayList<>();
String oId = getFieldValue(node, idName).toString();
for (T child : list) {
String tParentId = getFieldValue(child, parentIdName).toString();
if (tParentId.equals(oId)) {
tlist.add(child);
}
}
return tlist;
}
/**
* 判断是否有子节点
* @param list
* @param t
* @param idName
* @param parentIdName
* @return
* @param <T>
*/
private static <T> boolean hasChild(List<T> list, T t, String idName, String parentIdName) {
return getChildList(list, t, idName, parentIdName).size() > 0;
}
/**
* 通过Map方式构建树
* @param list 列表
* @param idName id名称
* @param parentIdName 父id名称
* @param childrenName 子节点列表名称
* @param topParentIdVal 顶层节点父id的值
* @return
* @param <T>
*/
public static <T> List<T> buildTreeByMap(List<T> list,String idName,String parentIdName,String childrenName,String topParentIdVal) {
if (CollectionUtils.isEmpty(list)) {
return Collections.emptyList();
}
//根据parentId进行分组
Map<String, List<T>> mapList = list.stream().collect(Collectors.groupingBy(o -> getFieldValue(o, parentIdName).toString()));
//给每个节点设置子节点列表
list.forEach(node -> setFieldValue(node, mapList.get(getFieldValue(node, idName).toString()), childrenName));
return list.stream().filter(o -> topParentIdVal.equals(getFieldValue(o, parentIdName))).collect(Collectors.toList());
}
/**
* 通过两层for循环方式构建树
* @param list 列表
* @param idName id名称
* @param parentIdName 父id名称
* @param childrenName 子节点列表名称
* @param topParentIdVal 顶层节点父id的值
* @return
* @param <T>
*/
public static <T> List<T> buildTreeByTwoLayersFor(List<T> list, String idName, String parentIdName, String childrenName, String topParentIdVal) {
List<T> resultList = new ArrayList<>();
for (T node : list) {
//如果是顶层节点
if (topParentIdVal.equals(getFieldValue(node, parentIdName))) {
resultList.add(node);
}
for (T child : list) {
if (getFieldValue(child, parentIdName).equals(getFieldValue(node, idName))) {
List<T> childrenList = (List<T>) getFieldValue(node, childrenName);
if (CollectionUtils.isEmpty(childrenList)) {
childrenList = new ArrayList<>();
setFieldValue(node, childrenList, childrenName);
}
childrenList.add(child);
}
}
}
return resultList;
}
/**
* 获取属性值
* @param o 对象
* @param fieldName 属性名
* @return
*/
private static Object getFieldValue(Object o, String fieldName) {
try {
Class<?> oClass = o.getClass();
Field field = oClass.getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(o);
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
/**
* 设置字段值
* @param o 对象
* @param val 值
* @param fieldName 属性名
*/
private static void setFieldValue(Object o, Object val, String fieldName) {
try {
Class<?> oClass = o.getClass();
Field field = oClass.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(o, val);
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
package com.demo;
import cn.hutool.core.date.DateTime;
import com.cnpc.epai.assetcatalog.util.TreeUtil;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
public class Demo01 {
public static void main(String[] args) {
List<NodeTree> nodeTreeList = initializeListNodeTree();
Long bing = System.currentTimeMillis();
//通过map方式组装tree
List<NodeTree> nodeMapList = TreeUtil.buildTreeByMap(nodeTreeList,"id", "parentId", "children", "root");
Long end = System.currentTimeMillis();
Long da = end-bing;
System.out.println("nodeMapList 时间:"+da);
Long bing1 = System.currentTimeMillis();
//通过递归方式构建树组装tree
List<NodeTree> nodeFnList = TreeUtil.buildTreeByRecursion(nodeTreeList,"id", "parentId", "children");
Long end1 = System.currentTimeMillis();
Long da1 = end1-bing1;
System.out.println("nodeFnList 时间:"+da1);
Long bing2 = System.currentTimeMillis();
//通过两层for循环方式构建tree
List<NodeTree> nodeToFnList = TreeUtil.buildTreeByTwoLayersFor(nodeTreeList,"id", "parentId", "children","root");
Long end2 = System.currentTimeMillis();
Long da2 = end2-bing2;
System.out.println("nodeToFnList 时间:"+da2);
}
/**
* 初始化 NodeTree 列表
* @return
*/
public static List<NodeTree> initializeListNodeTree(){
List<NodeTree> treeList = new ArrayList<>();
for(int j = 1 ; j <= 5 ; j++){
NodeTree tree = new NodeTree();
tree.setId(j+"");
tree.setParentId("root");
tree.setDateTime(new DateTime());
treeList.add(tree);
}
for(int i = 6; i < 1000 ; i++){
NodeTree tree = new NodeTree();
tree.setId(i+"");
tree.setParentId("1");
tree.setDateTime(new DateTime());
treeList.add(tree);
}
for(int i = 1000; i < 2000 ; i++){
NodeTree tree = new NodeTree();
tree.setId(i+"");
tree.setParentId("2");
tree.setDateTime(new DateTime());
treeList.add(tree);
}
for(int i = 2000; i < 3000 ; i++){
NodeTree tree = new NodeTree();
tree.setId(i+"");
tree.setParentId("3");
tree.setDateTime(new DateTime());
treeList.add(tree);
}
for(int i = 3000; i < 4000 ; i++){
NodeTree tree = new NodeTree();
tree.setId(i+"");
tree.setParentId("4");
tree.setDateTime(new DateTime());
treeList.add(tree);
}
for(int i = 4000; i < 5000 ; i++){
NodeTree tree = new NodeTree();
tree.setId(i+"");
tree.setParentId("5");
tree.setDateTime(new DateTime());
treeList.add(tree);
}
for(int i = 5000; i < 6000 ; i++){
NodeTree tree = new NodeTree();
tree.setId(i+"");
tree.setParentId("6");
tree.setDateTime(new DateTime());
treeList.add(tree);
}
return treeList;
}
}
/**
* 节点对象
* 这个类用的 lombok 所以没有get、set方法
*/
@Data
class NodeTree{
private String id; //id
private String parentId; //父节点id
private DateTime dateTime; //时间,可用于排序
private List<NodeTree> children; //子集
}