Java递归生成树

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.youkuaiyun.com/xqnode/article/details/79639106
1.建菜单表

CREATE TABLE `t_menu` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `pid` int(11) NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4;

2.造一些数据
在这里插入图片描述
3.撸代码
这里只展示递归生成树的代码,查询数据库的操作非常简单,只用到了一句sql,然后将结果封装成List。

select id, pid, `name` from t_menu 

service代码:

@Override
    public List<Menu> tree() {
        List<Menu> menus = menuMapper.selectAll();
        return createTree(0, menus);
    }

    private List<Menu> createTree(int pid, List<Menu> menus) {
        List<Menu> treeMenu = new ArrayList<>();
        for (Menu menu : menus) {
            if (pid == menu.getPid()) {
                treeMenu.add(menu);
                menu.setChildren(createTree(menu.getId(), menus));
            }
        }
        return treeMenu;
    }

返回数据格式如下:
在这里插入图片描述
end

无限级Java递归) 2007-02-08 10:26 这几天,用java写了一个无限极的递归写的,可能代码不够简洁,性能不够好,不过也算是练习,这几天再不断改进。前面几个小图标的判断,搞死我了。 package com.nickol.servlet; import java.io.IOException; import java.io.PrintWriter; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.ArrayList; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.nickol.utility.DB; public class category extends HttpServlet { /** * The doGet method of the servlet. * * This method is called when a form has its tag value method equals to get. * * @param request the request send by the client to the server * @param response the response send by the server to the client * @throws ServletException if an error occurred * @throws IOException if an error occurred */ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setCharacterEncoding("utf-8"); response.setContentType("text/html"); PrintWriter out = response.getWriter(); out .println(""); out.println(""); out.println(" Category" + "" + "body{font-size:12px;}" + "" + "" + ""); out.println(" "); out.println(showCategory(0,0,new ArrayList(),"0")); out.println(" "); out.println(""); out.flush(); out.close(); } public String showCategory(int i,int n,ArrayList frontIcon,String countCurrent){ int countChild = 0; n++; String webContent = new String(); ArrayList temp = new ArrayList(); try{ Connection conn = DB.GetConn(); PreparedStatement ps = DB.GetPs("select * from category where pid = ?", conn); ps.setInt(1, i); ResultSet rs = DB.GetRs(ps); if(n==1){ if(rs.next()){ webContent += "";//插入结尾的减号 temp.add(new Integer(0)); } webContent += " ";//插入站点图标 webContent += rs.getString("cname"); webContent += "\n"; webContent += showCategory(Integer.parseInt(rs.getString("cid")),n,temp,"0"); } if(n==2){ webContent += "\n"; }else{ webContent += "\n"; } while(rs.next()){ for(int k=0;k<frontIcon.size();k++){ int iconStatic = ((Integer)frontIcon.get(k)).intValue(); if(iconStatic == 0){ webContent += "";//插入空白 }else if(iconStatic == 1){ webContent += "";//插入竖线 } } if(rs.isLast()){ if(checkChild(Integer.parseInt(rs.getString("cid")))){ webContent += "";//插入结尾的减号 temp = (ArrayList)frontIcon.clone(); temp.add(new Integer(0)); }else{ webContent += "";//插入结尾的直角 } }else{ if(checkChild(Integer.parseInt(rs.getString("cid")))){ webContent += "";//插入未结尾的减号 temp = (ArrayList)frontIcon.clone(); temp.add(new Integer(1)); }else{ webContent += "";//插入三叉线 } } if(checkChild(Integer.parseInt(rs.getString("cid")))){ webContent += " ";//插入文件夹图标 }else{ webContent += " ";//插入文件图标 } webContent += rs.getString("cname"); webContent += "\n"; webContent += showCategory(Integer.parseInt(rs.getString("cid")),n,temp,countCurrent+countChild); countChild++; } webContent += "\n"; DB.CloseRs(rs); DB.ClosePs(ps); DB.CloseConn(conn); }catch(Exception e){ e.printStackTrace(); } return webContent; } public boolean checkChild(int i){ boolean child = false; try{ Connection conn = DB.GetConn(); PreparedStatement ps = DB.GetPs("select * from category where pid = ?", conn); ps.setInt(1, i); ResultSet rs = DB.GetRs(ps); if(rs.next()){ child = true; } DB.CloseRs(rs); DB.ClosePs(ps); DB.CloseConn(conn); }catch(Exception e){ e.printStackTrace(); } return child; } } --------------------------------------------------------------------- tree.js文件 function changeState(countCurrent,countChild){ var object = document.getElementById("level" + countCurrent + countChild); if(object.style.display=='none'){ object.style.display='block'; }else{ object.style.display='none'; } var cursor = document.getElementById("cursor" + countCurrent + countChild); if(cursor.src.indexOf("images/tree_minus.gif")>=0) {cursor.src="images/tree_plus.gif";} else if(cursor.src.indexOf("images/tree_minusbottom.gif")>=0) {cursor.src="images/tree_plusbottom.gif";} else if(cursor.src.indexOf("images/tree_plus.gif")>=0) {cursor.src="images/tree_minus.gif";} else {cursor.src="images/tree_minusbottom.gif";} var folder = document.getElementById("folder" + countCurrent + countChild); if(folder.src.indexOf("images/icon_folder_channel_normal.gif")>=0){ folder.src = "images/icon_folder_channel_open.gif"; }else{ folder.src = "images/icon_folder_channel_normal.gif"; }
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 可能是更好的选择;而对于性能敏感的应用场景,则可能需要权衡代码复杂度和执行效率,考虑使用迭代或其他数据处理机制。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值