Java List 递归生成树形结构

本文介绍了一种使用Java实现的从列表数据生成树形结构的方法,并通过枚举类型实例展示了具体的应用过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

@Data
public class BaseTree<T extends BaseTree<T>> {
    
    private static final long serialVersionUID = 1L;

    @TableId(value = "id",type = IdType.AUTO)
    private Long id;

    private Long parentId;

    @TableField(exist = false)
    @JsonInclude(JsonInclude.Include.NON_EMPTY)
    private List<T> children = new ArrayList<>();
    
    public BaseTree() {}

    /**
      * 注意:children一定要new ArrayList<>();不然add会报错的
      * 核心思想就是先拿出list中所有的parentId,再拿出所有id,做差集 拿到的就是一级类目 这里对parentCode为空的数据赋了0值, 如果是固定值可以直接filter 0的数据
      * 递归一级类目下的二级类目,再递归二级类目下的三级类目。。。然后把查到的相应子类目加入到父节点中
      */
    public static <T extends BaseTree<T>> List<T> listToTree(List<T> list) {
        list.forEach(item->{
           if(StringUtils.isBlank(item.getParentCode())){
               item.setParentCode("0");
           }
       });
        Set<Long> parentIds = list.stream().map(BaseTree::getParentId).collect(Collectors.toSet());
        Set<Long> ids = list.stream().map(BaseTree::getId).collect(Collectors.toSet());
        parentIds.removeAll(ids);
        // 我这里可以直接用这个
        // Set<String> parentIds = list.stream().filter(item->item.getParentCode().equals("0")).map(Category::getParentCode).collect(Collectors.toSet());
        //递归查找子结点
        return list.stream()
                   .filter(tree -> parentIds.contains(tree.getParentId()))
                   .map(tree -> findChildren(tree, list))
                   .collect(Collectors.toList());
    }

    private static <T extends BaseTree<T>> T findChildren(T tree, List<T> list) {
        list.stream()
            .filter(node -> node.getParentId().equals(tree.getId()))
            .map(node -> findChildren(node, list))
            .forEachOrdered(children -> tree.getChildren().add(children));
        return tree;
    }

   
    
}

也可以直接写在所在类的方法中

    public List<BasMallCatalogDTO> listToTree(List<BasMallCatalogDTO> list) {
        list.forEach(item->{
           if(StringUtils.isBlank(item.getParentCode())){
               item.setParentCode("0");
           }
       });
        Set<Long> parentIds = list.stream().map(BasMallCatalogDTO::getParentId).collect(Collectors.toSet());
        Set<Long> ids = list.stream().map(BasMallCatalogDTO::getId).collect(Collectors.toSet());
        parentIds.removeAll(ids);
        // 我这里可以直接用这个
        // Set<String> parentIds = list.stream().filter(item->item.getParentCode().equals("0")).map(Category::getParentCode).collect(Collectors.toSet());
        //递归查找子结点
        return list.stream()
                .filter(tree -> parentIds.contains(tree.getParentId()))
                .map(tree -> findChildren(tree, list))
                .collect(Collectors.toList());
    }

    private BasMallCatalogDTO findChildren(BasMallCatalogDTO tree, List<BasMallCatalogDTO> list) {
        list.stream()
                .filter(node -> node.getParentId().equals(tree.getId()))
                .map(node -> findChildren(node, list))
                .forEachOrdered(children -> tree.getChildren().add(children));
        return tree;
    }

 2024-8-5 16:59:23 枚举转树举例, 两种方法


import cn.hutool.core.util.ObjectUtil;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author chenyc51748
 */
public class CategoryUtil {

    /**
     * 定义枚举类型
     */
    public enum CategoryEnum {
        /**
         * 关联主体分类
         */

        /**
         * 监管机构分类 type:regulatory_agencies
         * 这里一级分类的parentCode为空用main中listToTree 如果固定为0 用listToTreeTemp
         */
        XXX(null, "XXX", "金融监管", null, "regulatory_agencies"),
        YYY(44, "YYY", "国家外汇管理局", "XXX", "regulatory_agencies"),
        ZZZ(45, "ZZZ", "监管", "YYY", "regulatory_agencies"),
        ;
        // 其他分类...


        /**
         * 数据库中分类数值 (不唯一 关联主体、监管机构...之间的是有相同的 父级分类id是null )
         */
        private final Integer id;
        /**
         * 分类编码 唯一值 用来做转树结构
         */
        private final String code;
        /**
         * 分类名称
         */
        private final String name;
        /**
         * 父类编码
         */
        private final String parentCode;
        /**
         * 分类类型
         */
        private final String type;

        CategoryEnum(Integer id, String code, String name, String parentCode, String type) {
            this.id = id;
            this.code = code;
            this.name = name;
            this.parentCode = parentCode;
            this.type = type;
        }

        public Integer getId() {
            return id;
        }

        public String getCode() {
            return code;
        }

        public String getName() {
            return name;
        }

        public String getParentCode() {
            return parentCode;
        }

        public String getType() {
            return type;
        }

    }

    public static class Category {
        private Integer id;
        private String code;
        private String name;
        // 父分类代码,可能为 null
        private String parentCode;
        private String type;
        // 子类集合
        private List<Category> subCategories;

        public Category(Integer id, String code, String name, String parentCode, String type) {
            this.id = id;
            this.code = code;
            this.name = name;
            this.parentCode = parentCode;
            this.type = type;
            this.subCategories = new ArrayList<>();
        }

        public Integer getId() {
            return id;
        }

        public void setId(Integer id) {
            this.id = id;
        }

        public String getCode() {
            return code;
        }

        public void setCode(String code) {
            this.code = code;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getParentCode() {
            return parentCode;
        }

        public void setParentCode(String parentCode) {
            this.parentCode = parentCode;
        }

        public List<Category> getSubCategories() {
            return subCategories;
        }

        public void setSubCategories(List<Category> subCategories) {
            this.subCategories = subCategories;
        }

        public void addSubCategory(Category subCategory) {
            this.subCategories.add(subCategory);
        }

        public String getType() {
            return type;
        }

        public void setType(String type) {
            this.type = type;
        }

        @Override
        public String toString() {
            return "Category{" +
                    "id=" + id +
                    ", code='" + code + '\'' +
                    ", name='" + name + '\'' +
                    ", parentCode='" + parentCode + '\'' +
                    ", type='" + type + '\'' +
                    ", subCategories=" + subCategories +
                    '}';
        }
    }

    /**
     * 将枚举列表转换为 Category 列表
     */
    private static List<Category> enumToList() {
        return Arrays.stream(CategoryEnum.values())
                .map(e -> new Category(e.getId(), e.getCode(), e.getName(), e.getParentCode(), e.getType()))
                .collect(Collectors.toList());
    }

    /**
     * 构建分类树并根据类型返回所有一级分类的列表
     */
    public static List<Category> listToTree(String type) {
        List<Category> allCategories = enumToList();
        Map<String, Category> categoryMap = allCategories.stream()
                .filter(category -> (type == null || type.isEmpty()) || category.getType().equals(type))
                .collect(Collectors.toMap(Category::getCode, Function.identity()));

        List<Category> rootCategories = new ArrayList<>();
        for (Category category : categoryMap.values()) {
            if (category.getParentCode() == null || "0".equals(category.getParentCode())) {
                rootCategories.add(category);
            } else {
                Category parent = categoryMap.get(category.getParentCode());
                if (parent != null) {
                    parent.addSubCategory(category);
                }
            }
        }

        // 递归地构建子分类树
        buildSubCategoriesTree(rootCategories, categoryMap);
        return rootCategories;
    }
    // 递归调用
    private static void buildSubCategoriesTree(List<Category> categories, Map<String, Category> categoryMap) {
        for (Category category : categories) {
            List<Category> children = categoryMap.values().stream()
                    .filter(child -> child.getParentCode() != null && child.getParentCode().equals(category.getCode()))
                    .collect(Collectors.toList());
            category.setSubCategories(children);
            if (!children.isEmpty()) {
                buildSubCategoriesTree(children, categoryMap);
            }
        }
    }

    /**
     * 更新 getCategoryByCode 方法以接受 type 参数并进行筛选
     */
    public static List<Category> getCategoryByCode(String code, String type) {
        // 使用 type 参数筛选
        List<Category> allCategories = listToTree(type);
        List<Category> res = Lists.newArrayList();
        Category temp = allCategories.stream()
                .filter(category -> category.getCode().equals(code))
                .findFirst()
                .orElse(null);
        if (ObjectUtil.isNotEmpty(temp)) {
            res.add(temp);
        }
        return res;
    }
    // 主方法,用于验证
    public static void main(String[] args) {
        // 获取所有一级分类及其子分类的树形结构列表
        // 第一种方法
        List<Category> categories = listToTree("XXX");
        List<Category> allCategories = listToTree(null);
        // 根据指定code拿数据
        // List<Category> res = getCategoryByCode(specificCode, type);
        System.out.println(res);

        // 第二种方法
        List<Category> categories1 = enumToList();
        List<Category> collect = listToTreeTemp(categories1);
        System.out.println(collect);
    }
    public static List<Category> listToTreeTemp(List<Category> list) {
        list.forEach(item->{
           if(StringUtils.isBlank(item.getParentCode())){
               item.setParentCode("0");
           }
       });
        Set<String> parentIds = list.stream().map(Category::getParentCode).collect(Collectors.toSet());
        Set<String> ids = list.stream().map(Category::getCode).collect(Collectors.toSet());
        parentIds.removeAll(ids);
        // 我这里可以直接用这个
        // Set<String> parentIds = list.stream().filter(item->item.getParentCode().equals("0")).map(Category::getParentCode).collect(Collectors.toSet());
        //递归查找子结点
        return list.stream()
                .filter(tree -> parentIds.contains(tree.getParentCode()))
                .map(tree -> findChildren(tree, list))
                .collect(Collectors.toList());
    }

    public static  Category findChildren(Category tree, List<Category> list) {
        list.stream()
                .filter(node -> node.getParentCode().equals(tree.getCode()))
                .map(node -> findChildren(node, list))
                .forEachOrdered(children -> tree.getSubCategories().add(children));
        return tree;
    }

}

2025-3-5 13:50:32

需求:只填充指定id的树结构
 

// list为所有部门数据 现在没有树形结构
public List<Dept> listToTree(List<Dept> list, List<Long> targetIds) {
        // 将所有部门按 id 分组
        Map<Long, Dept> deptMap = list.stream()
                .collect(Collectors.toMap(Dept::getId, dept -> dept));

        // 构建子节点缓存
        Map<Long, List<Dept>> childrenCache = new HashMap<>();
        for (Dept dept : list) {
            if (!childrenCache.containsKey(dept.getParentId())) {
                childrenCache.put(dept.getParentId(), new ArrayList<>());
            }
            childrenCache.get(dept.getParentId()).add(dept);
        }

        // 获取所有目标 id 的子节点
        List<Dept> result = new ArrayList<>();
        for (Long id : targetIds) {
            if (deptMap.containsKey(id)) {
                result.add(buildTree(deptMap.get(id), childrenCache));
            }
        }

        return result;
    }

    private Dept buildTree(Dept tree, Map<Long, List<Dept>> childrenCache) {
        // 获取当前节点的子节点
        List<Dept> children = childrenCache.getOrDefault(tree.getId(), new ArrayList<>());
        children.forEach(child -> buildTree(child, childrenCache));
        tree.setChildren(children);
        return tree;
    }

<think>好的,用户想用Java 8实现递归遍历树形结构的示例。首先,我需要确定用户的需求是什么。树形结构的遍历通常有几种方式:前序、后序、中序(二叉树)以及层序。用户提到的是递归实现,所以可能指的是前序、后序这些深度优先的方式,而层序通常用迭代实现,比如BFS。 接下来,我需要回忆Java中如何处理树结构。通常,树节点会有一个数据字段和子节点列表。例如,定义一个Node类,包含T类型的data和List<Node<T>> children。然后递归遍历的话,前序遍历就是先访问当前节点,再递归处理每个子节点;后序遍历则相反,先处理子节点再访问自己。 然后,考虑到用户提到Java 8,可能需要使用一些新特性,比如Lambda表达式或者Stream API来简化代码。比如在遍历子节点时,可以用children.stream().forEach(this::traversePreOrder),这样代码更简洁。 接下来需要检查引用内容。引用[1]中的示例代码是Java的,用递归遍历所有节点,先打印当前节点,然后递归遍历子节点。这实际上是前序遍历。用户的问题可能与此类似,但需要更详细的示例,可能包括不同遍历方式的实现。 引用[4]提到BFS通常用层序,但用户问的是递归,而递归一般用于DFS,所以可能需要区分不同的遍历方法。用户可能需要前序、后序的例子,以及如何用Java 8的特性编写。 然后,我需要构建一个示例代码。定义一个Node类,包含数据和子节点列表。然后写前序、后序的方法。例如,前序遍历方法先处理当前节点,然后对每个子节点递归调用自身。使用Java 8的Stream API来遍历子节点,可能更简洁。 还需要考虑用户可能的疑问,比如如何处理空节点或空子节点列表。在示例代码中,确保在遍历子节点前检查是否为空,或者使用Stream来处理空集合,这样更安全。 另外,是否需要返回遍历结果的列表?比如,将节点数据收集到一个List中,这样用户可以看到遍历顺序。在示例代码中添加这样的功能可能更实用。 最后,生成相关问题,帮助用户进一步学习,比如比较递归与迭代的优缺点,或者如何用Lambda优化代码,以及处理大型树时的栈溢出问题。</think>以下是用Java 8实现递归树形结构遍历的详细方法及示例代码: ### 一、树节点定义 ```java class Node<T> { private T data; private List<Node<T>> children = new ArrayList<>(); // 构造函数及访问方法 public Node(T data) { this.data = data; } public void addChild(Node<T> node) { children.add(node); } public List<Node<T>> getChildren() { return Collections.unmodifiableList(children); } public T getData() { return data; } } ``` ### 二、递归遍历实现 #### 1. 前序遍历(Pre-order) $$访问顺序 = 根节点 \rightarrow 子节点_1 \rightarrow 子节点_2 \rightarrow ...$$ ```java void traversePreOrder(Node<?> node) { System.out.println(node.getData()); // 先处理当前节点 node.getChildren().forEach(this::traversePreOrder); // Java8方法引用 } ``` #### 2. 后序遍历(Post-order) $$访问顺序 = 子节点_1 \rightarrow 子节点_2 \rightarrow ... \rightarrow 根节点$$ ```java void traversePostOrder(Node<?> node) { node.getChildren().forEach(this::traversePostOrder); System.out.println(node.getData()); // 最后处理当前节点 } ``` ### 三、Java8特性增强 使用Lambda表达式实现带操作的遍历: ```java void processTree(Node<String> root) { Consumer<Node<String>> nodeProcessor = n -> { System.out.println("Processing: " + n.getData()); // 可添加其他处理逻辑 }; traverseWithLambda(root, nodeProcessor); } private void traverseWithLambda(Node<String> node, Consumer<Node<String>> processor) { processor.accept(node); node.getChildren().forEach(child -> traverseWithLambda(child, processor)); } ``` ### 四、注意事项 1. **终止条件**:虽然空子节点列表会自动终止递归,但建议显式判断`if (node == null) return` 2. **栈溢出风险**:当树深度超过JVM栈大小时,建议改用迭代方式[^4] 3. **并行处理**:Java8可使用`node.getChildren().parallelStream()`实现并行遍历
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值