利用递归算法生成树形list

直接上代码,代码里面的注释能够讲清楚代码用意。

import com.alibaba.fastjson.JSONArray;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by F.S.ZH on 2017/3/8.
 */
public class RecursionMain {
    public static void main(String[] args) {
        /*以下的代码用于生成一个长度为20的平滑list(用pid表示父节点),模拟从二维数据表里面查询数据表里面查询的数据*/
        List<MetadataModel> metadataModelList = new ArrayList<MetadataModel>();
        for (int i = 0; i < 20 ; i++) {
            MetadataModel metadata = new MetadataModel();
            metadata.setId(String.valueOf(i));
            if (i != 0 && i != 1) {
                if (i != 0 && i % 5 == 0) {
                    metadata.setParentId("4");
                } else if (i != 0 && i % 4 == 0) {
                    metadata.setParentId("0");
                } else if (i != 0 && i % 7 == 0) {
                    metadata.setParentId("1");
                } else {
                    metadata.setParentId("7");
                }
            }
//            System.out.println(metadata.getId() + "," + metadata.getParentId() + ";");
            metadataModelList.add(metadata);
        }
        /*以下代码用于取出最顶级节点*/
        List<TreeModel> newTreeList = new ArrayList<TreeModel>();
        for (int i = 0; i < metadataModelList.size(); i++) {
            if (metadataModelList.get(i).getParentId() == null){
                TreeModel newTreeModel = new TreeModel();
                newTreeModel.setId(metadataModelList.get(i).getId());
                newTreeModel.setChildren(null);
                newTreeList.add(newTreeModel);
            }
        }
        /*以下代码用于获取除顶级节点外的所有节点*/
        List<TreeModel> paramTree = new ArrayList<TreeModel>();
        for (int i = 0; i < metadataModelList.size(); i++) {
            if (metadataModelList.get(i).getParentId() != null) {
                TreeModel paramTreeModel = new TreeModel();
                paramTreeModel.setId(metadataModelList.get(i).getId());
                paramTreeModel.setParentid(metadataModelList.get(i).getParentId());
                paramTree.add(paramTreeModel);
            }
        }
        /*为了看到更好的效果,加上第四级节点*/
        TreeModel addLevel = new TreeModel();
        addLevel.setId("21");
        addLevel.setParentid("5");
        paramTree.add(addLevel);
        /*生成最终的树形list(包含list的list)*/
        List<TreeModel> finalTree = new ArrayList<TreeModel>();
        for (int i = 0; i < newTreeList.size(); i++) {
            finalTree.add(recursionChildren(newTreeList.get(i), paramTree));
        }
        /*将list转换成json字符串,用到ali的fastjosn,是一个比较好用的java json工具*/
        JSONArray js = new JSONArray();
        js.addAll(finalTree);
        System.out.println(js.toJSONString());
    }

    /**
     * 将平滑的list转换成树形list,主要用到递归
     * @param treeModel
     * @param list
     * @return
     */
    public static TreeModel recursionChildren(TreeModel treeModel, List<TreeModel> list){
        /*如果一个节点的父id等于参数节点的id,则把这个节点写入参数节点的子节点list*/
        List<TreeModel> children = new ArrayList<TreeModel>();
        for (int i = 0; i < list.size(); i++) {
            if (list.get(i).getParentid().equals(treeModel.getId())) {
                children.add(list.get(i));
            }
        }
        /*如果子节点list中有对象存在,则用递归去寻找子节点的子节点,直到不再有子节点*/
        List<TreeModel> param = new ArrayList<TreeModel>();
        for (TreeModel childTree : children) {
            TreeModel grandChild = recursionChildren(childTree,list);
            param.add(grandChild);
        }
        /*最终返回传进来的带有所有子节点的参数节点*/
        treeModel.setChildren(param);
        return treeModel;
    }
}

 为了代码的完整性,我把pojo代码也贴上

/**
 * Created by F.S.ZH on 2017/3/8.
 * 用于生成平滑的带有父id的list
 */
public class MetadataModel {
    private String id;
    private String parentId;

    public String getId() {
        return id;
    }

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

    public String getParentId() {
        return parentId;
    }

    public void setParentId(String parentId) {
        this.parentId = parentId;
    }
}
import java.util.List;

/**
 * Created by F.S.ZH on 2017/3/8.
 * 用于最终生成树形list
 */
public class TreeModel {
    private String id;
    private String parentid;
    private List<TreeModel> children;

    public String getId() {
        return id;
    }

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

    public String getParentid() {
        return parentid;
    }

    public void setParentid(String parentid) {
        this.parentid = parentid;
    }

    public List<TreeModel> getChildren() {
        return children;
    }

    public void setChildren(List<TreeModel> children) {
        this.children = children;
    }
}

 

转载于:https://my.oschina.net/u/3307081/blog/860532

Java Stream API 提供了一种基于函数式编程风格的数据处理方式,可以用来简化并行操作、数据转换等任务。虽然 Java Streams 并不是直接用于生成树结构的工具,但它们能够非常方便地配合其他 Java 类库(如 Apache Commons Lang 的 RecursiveTreeBuilder 或自定义算法)来构建或操作树结构。 在讨论如何使用 Java Stream API 来递归生成树之前,我们需要了解基本的树结构及其关键组件: - **节点**:树的基本单位,通常包含数据和指向其子节点的引用。 - **根节点**:树的最顶级节点,无父节点。 - **子节点**:每个非叶子节点都有一个或多个子节点。 ### 使用 Java Stream 实现树的构建 虽然 Java Stream 主要用于处理集合,并非直接用于递归生成树,但在某种程度上,通过将递归过程转换为迭代式,我们可以在一定程度上利用 Stream 来构建树状结构。下面是一个简单的示例,展示如何使用 Stream 构建树结构。假设我们有一个代表树节点的简单类 `TreeNode`: ```java class TreeNode { String value; List<TreeNode> children; public TreeNode(String value) { this.value = value; this.children = new ArrayList<>(); } // 添加子节点 public void addChild(TreeNode child) { children.add(child); } } ``` #### 示例:使用递归来创建树结构 下面的例子展示了如何使用递归Java Streams 的组合来创建树结构。在这个例子中,我们将从一个列表开始,其中包含了父节点与子节点的关系,然后逐步构建树结构。 ```java public class TreeBuilder { public static TreeNode buildTree(List<NodePair> nodePairs) { return nodePairs.stream() .reduce(new TreeNode(null), (parent, next) -> { if (next.getParent() == null || parent.getValue().equals(next.getParent())) { parent.addChild(new TreeNode(next.getValue())); return parent; } else { return null; // 这里只是举例,实际情况下需要更复杂的逻辑来调整路径 } }, (left, right) -> left); // 使用空值作为初始节点,最终返回构建完成的根节点 // NodePair 类表示一个节点及其父节点名称 class NodePair { String value; String parent; public NodePair(String value, String parent) { this.value = value; this.parent = parent; } public String getParent() { return parent; } public String getValue() { return value; } } } } // 测试数据 List<NodePair> nodePairs = Arrays.asList( new NodePair("nodeB", "nodeA"), new NodePair("nodeD", "nodeC"), new NodePair("nodeE", "nodeC") ); TreeNode root = TreeBuilder.buildTree(nodePairs); root.getChildren().forEach(System.out::println); // 打印树的所有节点以验证结果 ``` 请注意,上述代码仅展示了如何将数据映射到树结构的基础概念。实际上,在构建树的过程中可能涉及到更复杂的问题,比如循环依赖检查、优化路径查找或添加额外的属性到节点上等等。在真正的应用中,你可能需要设计更多的辅助类和逻辑来处理各种情况。此外,这个示例并没有使用实际的 Stream 减少机制,而是简单地使用了 reduce 操作来进行构建。对于大型树结构的构建,使用传统的 for 循环或递归可能会更高效。 ### 相关问题: 1. **如何在构建树过程中处理循环依赖问题?** - 当遇到循环依赖时,应采取策略来避免无限递归,例如,可以限制递归深度或使用图论中的拓扑排序来检测和处理循环。 2. **Stream 是否适用于大规模树结构的构建?** - 尽管 Stream API 提供了一个优雅的方式来处理集合和序列化操作,但对于构建大型或极其复杂的树结构,由于内存管理和并行计算的限制,可能需要考虑使用传统循环或其他非函数式编程技术。 3. **在实际项目中应该选择哪种方式构建树结构?** - 这取决于具体的业务需求和系统的性能约束。如果系统允许并发处理并且对代码的简洁性和易读性有较高要求,那么使用 Stream 可能是更好的选择;而对于性能敏感的应用场景,则可能需要权衡代码复杂度和执行效率,考虑使用迭代或其他数据处理机制。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值