递归树实现 Java

11 篇文章 0 订阅

前言

        不管是传统项目还是互联网电商项目,都会用到递归调用,比如传统的部门  等级,或者说商品的菜单目录,递归是循环调用,
    自己调用自己,两个问题比较明显,一个是效率问题,一个是一不小心就会导致OOM(Out Of  Memory)

思路

      递归分两种,一个是内存递归,一个是数据库递归,当然练习时,可以两种都写写比较一下,但是不用多说内存的效率那是没得说,
   接下来咱们就用代码实现一个递归

代码

/**
 * 实体类
 * @Classname Recursion
 * @Created by windBird
 */
public class Recursion implements Serializable {

    private static final long serialVersionUID = -8285127290179079661L;
  
    private   Integer  id; // 主键

    private  Integer pid;  //父id  与主键关联

    private  Integer icon; //递归对应的图标

    private Integer seq; //递归对应的顺序

    private Integer level;//递归的等级

    private String  title;  //显示的内容

    private List<Recursion> childrenList; //子类

    public Integer getId() {
        return id;
    }

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

    public Integer getPid() {
        return pid;
    }

    public void setPid(Integer pid) {
        this.pid = pid;
    }

    public Integer getIcon() {
        return icon;
    }

    public void setIcon(Integer icon) {
        this.icon = icon;
    }

    public Integer getSeq() {
        return seq;
    }

    public void setSeq(Integer seq) {
        this.seq = seq;
    }

    public Integer getLevel() {
        return level;
    }

    public void setLevel(Integer level) {
        this.level = level;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public List<Recursion> getChildrenList() {
        return childrenList;
    }

    public void setChildrenList(List<Recursion> childrenList) {
        this.childrenList = childrenList;
    }
}

统计递归关联次数
select 
t.id,
t.pid,t.name,
sum(case when t.id =n.name_id then 1 else 0 end) as total   from tb_name t 
left join tb_name_shop n on t.id =n.name_id
group by t.id
################ 具体书写##################
/**
 * @Description  具体实现
 * @Date 2020/11/28 11:02
 * @Created by windBird
 */
public class RecursionPractise {
    public static void main(String[] args) {
        List<Recursion> resultData = new ArrayList<>(); //最终返回的结果
        List<Recursion> recursions = new ArrayList<>(); //递归的单个对象
        getData(recursions);
        //递归树逻辑编写 
        resultData = recursions.stream().filter(recursion -> recursion.getPid() == -1)
                .map(recursion -> covertRecursionCode(recursion, recursions)).collect(Collectors.toList());

        resultData.forEach(r-> System.out.println("r = " + r));
    }

    private static Recursion covertRecursionCode(Recursion recursion, List<Recursion> recursions) {
        Recursion node = new Recursion();
        BeanUtils.copyProperties(recursion,node);
        List<Recursion> childNode = recursions.stream().filter(childrenRecursion -> childrenRecursion.getPid() == recursion.getId())
                .map(childrenRecursion -> covertRecursionCode(childrenRecursion, recursions)).collect(Collectors.toList());
        node.setChildrenList(childNode);
        return node;
    };

    public static void getData(List<Recursion> recursions) {
        //查询数据库获取数据 这里自己构造
        Recursion recursion = new Recursion();
        recursion.setId(1);
        recursion.setPid(-1);
        recursion.setIcon(1);
        recursion.setTitle("递归树顶层");
        recursion.setLevel(1);
        recursion.setSeq(0);
        recursions.add(recursion);
        Recursion recursion1 = new Recursion();
        recursion1.setId(2);
        recursion1.setPid(1);
        recursion1.setIcon(2);
        recursion1.setTitle("递归树次顶层");
        recursion1.setLevel(2);
        recursion1.setSeq(1);
        recursions.add(recursion1);
        Recursion recursion2 = new Recursion();
        recursion2.setId(3);
        recursion2.setPid(1);
        recursion2.setIcon(1);
        recursion2.setTitle("递归树次顶层");
        recursion2.setLevel(2);
        recursion2.setSeq(2);
        recursions.add(recursion2);

        Recursion recursion3 = new Recursion();
        recursion3.setId(4);
        recursion3.setPid(2);
        recursion3.setIcon(1);
        recursion3.setTitle("递归树次次顶层");
        recursion3.setLevel(3);
        recursion3.setSeq(0);
        recursions.add(recursion3);
    }
}

### 树转集合
 private static List<Recursion> treeToList(List<Recursion> messageList) {
        List<Recursion> result = new ArrayList<>();
        messageList.forEach(m->{
            result.add(m);
            List<Recursion> childrenList = m.getChildrenList();
            if(!CollectionUtils.isEmpty(childrenList)){
                List<Recursion> childrenListAgain = treeToList(childrenList);
                result.addAll(childrenListAgain);
            }
        });
        if(result.size() > 0) result.forEach(r-> r.setChildrenList(null));
        return result;
    }

结果展示

递归树顶级

二级

二级展现
3级展现

友情提示

1.靠内存实现递归,减少与数据库的磁盘交互
2.表设计的关键,id 与p_id 需要自关联,其他字段根据项目需要添加
3.实体类的设计,必须有List <XXX> 集合节点
4.自己指定一个根节点的标记,比如 p_id 给个 -1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
无限级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"; }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值