文章目录
- 递归封装数结构
- 追忆
- 代码
递归封装数结构
追忆
记得我刚开始工作的第一个模块就是获取菜单的功能。除了理解一个用户对应多个角色,一个角色对应多个权限之外。最棘手的就是前端要求返回树状结构。大概报文类似于:
Node {
id = 1, name = '根节点', parentId = 0, child = [Node {
id = 2, name = '二级节点', parentId = 1, child = [Node {
id = 4, name = '三级节点', parentId = 2, child = [Node {
id = 5, name = '四级节点', parentId = 4, child = null
}]
}]
}, Node {
id = 3, name = '二级节点', parentId = 1, child = null
}]
}
就是每一个节点会有一个List的属性,里面放的是他们的子节点那种(同理,我做的那个就是子菜单)。
当时这个功能做出来的时候我还是挺有成就感的。前两天看到了现在公司的那块逻辑,其实都差不多,有感而发,大晚上的写一遍,发篇博客吧。
代码
实体类代码:
package recursion.model;
import java.util.List;
/**
* @program: test
* @description: 递归测试节点
* @author: YangHang
* @create: 2019-08-24 02:27
**/
public class Node {
private int id;
private String name;
private int parentId;
private List<Node> child;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getParentId() {
return parentId;
}
public void setParentId(int parentId) {
this.parentId = parentId;
}
public List<Node> getChild() {
return child;
}
public void setChild(List<Node> child) {
this.child = child;
}
@Override
public String toString() {
return "Node{" +
"id=" + id +
", name='" + name + '\'' +
", parentId=" + parentId +
", child=" + child +
'}';
}
}
新建的java普通项目,没有引入lomlok之类的,凑合着看哈。
一般来说,这种实体类中会有自己的id和他上级的id,你要做的就是将父级id等于它的放到它的List属性中去。
这就需要递归,或者说是一种回溯算法。
如果你想真的了解递归,建议你去看一下堆栈的原理,看完之后相信你会有很深刻的认识,之后你就可以解决著名的算法题–“迷宫问题”。
扯远了。。。。。
package recursion.test;
import recursion.model.Node;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
* @program: test
* @description: 测试递归树
* @author: YangHang
* @create: 2019-08-24 02:29
**/
public class TestRecursion {
public static void main(String[] args) {
// 准备数据
List<Node> nodeList = Arrays.asList(
new Node() {{
this.setId(1);
this.setName("根节点");
this.setParentId(0);
}},
new Node() {{
this.setId(2);
this.setName("二级节点");
this.setParentId(1);
}},
new Node() {{
this.setId(3);
this.setName("二级节点");
this.setParentId(1);
}},
new Node() {{
this.setId(4);
this.setName("三级节点");
this.setParentId(2);
}},
new Node() {{
this.setId(5);
this.setName("四级节点");
this.setParentId(4);
}}
);
// System.out.println(nodeList);
// 获取根节点
Node rootNode = nodeList.get(0);
setChildNodeList(rootNode, nodeList);
System.out.println(rootNode);
}
// 设置所有节点的子节点
private static void setChildNodeList(Node node, List<Node> nodeList) {
if (ifHasChild(node, nodeList)) {
List<Node> allChildList = getAllChildList(node, nodeList);
allChildList.forEach(x ->
setChildNodeList(x, nodeList)
);
node.setChild(allChildList);
}
return;
}
// 获取一个节点的所有子节点集合
private static List<Node> getAllChildList(Node node, List<Node> nodeList) {
return nodeList.stream().filter(temp -> temp.getParentId() == node.getId()).collect(Collectors.toList());
}
// 判断该节点是否有子节点
private static boolean ifHasChild(Node node, List<Node> nodeList) {
for (Node temp : nodeList) {
if (temp.getParentId() == node.getId()) {
return true;
}
}
return false;
}
}
上面的逻辑循环的次数有点多,如果要用的话可以优化一下。