场景
笔者有一张分类表,表结构如下
-- 分类
drop table if exists `category`;
create table `category` (
`id` bigint not null comment 'id',
`parent` bigint not null default 0 comment '父id',
`name` varchar(50) not null comment '书名',
`sort` int comment '顺序',
primary key (`id`)
) engine=innodb default charset=utf8mb4 comment='父类表';
insert into `category` (id, parent, name, sort) values (100, 0, '前端', 100);
insert into `category` (id, parent, name, sort) values (101, 100, 'Vue', 101);
insert into `category` (id, parent, name, sort) values (102, 100, 'HTML & CSS', 102);
insert into `category` (id, parent, name, sort) values (200, 0, '后端', 200);
insert into `category` (id, parent, name, sort) values (201, 200, 'java', 201);
insert into `category` (id, parent, name, sort) values (202, 200, 'spring', 202);
insert into `category` (id, parent, name, sort) values (203, 200, '并发', 203);
insert into `category` (id, parent, name, sort) values (204, 200, '数据结构', 204);
复制代码
不难看出这是一张分类管理表,parent代表当前数据的父节点,若为0则代表是根节点。为了组装出一科树笔者思考再三选用递归进行组装。
关于递归
优点
代码更简洁清晰,可读性更好
缺点
时间和空间消耗比较大。每一次函数调用都需要在内存栈中分配空间以保存参数,返回地址以及临时变量,而且往栈里面压入数据和弹出都需要时间。
另外递归会有重复的计算。递归本质是把一个问题分解为多个问题,如果这多个问题存在重复计算,有时候会随着n成指数增长。斐波那契的递归就是一个例子。
递归还有栈溢出的问题,每个进程的栈容量是有限的。由于递归需要系统堆栈,所以空间消耗要比非递归代码要大很多。而且,如果递归深度太大,可能系统撑不住。
编码
从数据库中查出数据
List<Category> categoryList = categoryMapper.selectByExample(categoryExample);
复制代码
有了数据,开始分析递归算法思路
确定递归函数的功能
返回当前节点的子节点集合,例如当前节点id为100,则返回parent为100的节点的集合。
确定终止条件
这个递归函数会进行一次for循环,循环结束就代表遍历结束。
寻找重复的工作
从根节点开始,用自己的id去集合中找自己的子节点集合。查找到对应子节点,子节点也需要查找其所对应的子节点,所以也需要用自己id去集合中找自己的子节点,如此往复。
编写函数
注意这里笔者比较long类型的方式,说白就是Long类型-128, 127之间是从缓存中取出的,所以这个范围比较是没有问题,但是在这个范围以外会new对象,使用==比较的是地址肯定会返回false。具体原因可参考这篇博客
[# Java中判断两个Long类型是否相等](www.cnblogs.com/shenwen/p/1…)
public List<Category> list(CategoryReq req) {
logger.info("开始获取所有分类列表,请求参数{}", JSONUtil.toJsonStr(req));
CategoryExample categoryExample = new CategoryExample();
// List<Category> categoryList = categoryMapper.selectCategoryTree();
List<Category> categoryList = categoryMapper.selectByExample(categoryExample);
List<Category> categoryTree = getCategoryTree(categoryList);
// List<CategoryResp> respList=CopyUtil.copyList(categoryList, CategoryResp.class);
return categoryTree;
}
/**
* 使用递归完成树的组装
*
* @param categoryList
* @return
*/
private List<Category> getCategoryTree(List<Category> categoryList) {
List<Category> resultList = new ArrayList<>();
for (int i = 0; i < categoryList.size(); i++) {
Category category = categoryList.get(i);
// 若是根节点,则存入集合中 并开始找寻子节点
if (category.getParent().longValue() == 0L) {
// 初始化集合成员变量
category.setChildren(new ArrayList<>());
// 递归的开始,将查找的子节点集合存到自己的集合中
category.getChildren().addAll(getCategoryTree(categoryList, category.getId()));
resultList.add(category);
}
}
return resultList;
}
private List<Category> getCategoryTree(List<Category> categoryList, Long id) {
List<Category> resultList = new ArrayList<>();
for (int i = 0; i < categoryList.size(); i++) {
Category category = categoryList.get(i);
if (category.getParent().longValue() == id.longValue()) {
resultList.add(category);
category.setChildren(new ArrayList<>());
// 递归查找子节点对应的孙节点
category.getChildren().addAll(getCategoryTree(categoryList, category.getId()));
}
}
return resultList;
}
复制代码
近期评论