前言
不管是传统项目还是互联网电商项目,都会用到递归调用,比如传统的部门 等级,或者说商品的菜单目录,递归是循环调用,
自己调用自己,两个问题比较明显,一个是效率问题,一个是一不小心就会导致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;
}
结果展示
友情提示
1.靠内存实现递归,减少与数据库的磁盘交互
2.表设计的关键,id 与p_id 需要自关联,其他字段根据项目需要添加
3.实体类的设计,必须有List <XXX> 集合节点
4.自己指定一个根节点的标记,比如 p_id 给个 -1