目录
概要
最近的项目中用到了很多次树状数据结构,当时写得时候为了实现,没有考虑到代码的复用,每次需要使用树状结构算法怎都重新写一次递归方法。现在回头看代码写得有些臃肿,于是想着进一步优化项目中所有涉及到的递归算法。
问题分析
提示:
首先从数据库中查出数据(DataList),然后需要将列表结构的(DataList)数据转换为树状结构的数据(TreeData)。
项目中之所以写了多处递归算法,主要原因还是因为每个算法的入参数据类型不同,假如只想写一个递归算法供项目各处调用,那么必须解决入参数据类型不统一的问题。如何将不同数据类型,抽象为具有共同属性的同一类型。这里就需要考虑要用到泛型或超级类作为递归算法的入参就能够解决以上提到的问题。
泛型类的实现
提示:泛型的定义或者超级类型的定义很重要。
如果使用超级类的方式实现,则需要将所有转换为树状结构的类型继承超级类,这样有可能会影响到其他代码的改造,这里不建议使用继承超级类的方式,选用封装泛型类Tree<T>来实现通用递归算法。(代码使用java语言实现)
Tree类代码实现如下:
/**
* <p>封装树状实体类,有可以作为树状根类</p>
* @author 刘一份
*/
@Data
public class Tree<T> {
/**
* 当前节点ID
*/
private String id;
/**
* 当前节点名称
*/
private String text;
/**
* 父节点ID
*/
private String parentId;
/**
*当前节点下的子节点
*/
private List<Tree<T>> children = new ArrayList<>();
}
生成树状结构的方法
提示:将封装的泛型类(Tree)作为参数传入递归算法。
将列表数据(DataList)转换为树状结构(TreeData),有两个步骤,一是要先找到根节点,二是根据根节点依次添加子节点。
定义一个TreeUtil类型,分别实现生成根节点和添加子节点两个函数。
- 生成根节点的函数代码实现(即将列表数据(DataList)转换为树状结构(TreeData)):
/**
* 根据传入List数据和根节点ID值生成对应的树状结构
* @param dataList 需要转换成树状结构的原始集合
* @param rootID 根节点ID值(可能是空字符串、null等情形)
* @return 返回树状结构的集合
*/
public static <T> List<Tree<T>> generateTree(List<Tree<T>> dataList, String rootID) {
List<Tree<T>> trees = new ArrayList<>();
for (Tree<T> treeNode : dataList) {
if (rootID.equals(treeNode.getParentId())) {
trees.add(addChildren(treeNode, dataList));
}
}
return trees;
}
2.添加子节点的函数代码实现(即通过递归算法,添加每下一层子节点):
/**
* 递归完成添加每一层子节点
* @param parentNode 当前节点(父节点)
* @param dataList从原始集合列表中查找下一层节点(子节点)
* @return 返回添加好子节点之后的当前节点
*/
public static <T> Tree<T> addChildren(Tree<T> parentNode, List<Tree<T>> dataList) {
for (Tree<T> treeNode: dataList) {
if (parentNode.getId().equals(treeNode.getParentId())) {
if (parentNode.getChildren() == null) {
parentNode.setChildren(new ArrayList<>());
}
parentNode.getChildren().add(addChildren(treeNode, dataList));
}
}
return parentNode;
}
具体调用方法示例
/**
* 获取部门的树状结构数据
*/
public List<Tree<Dept>> getTree() {
List<Tree<Dept>> dataList= new ArrayList<>();
List<Dept> deptList= deptMapper.selectAll();
this.buildTrees(dataList,deptList);
return TreeUtil.generateTree(dataList,"");//根节点的父ID为""
}
/**
* 将需要转成树状结构的数据中必要数据赋值给Tree类型,
* 转为通用递归算法统一的入参格式
*/
private void buildTrees(List<Tree<City>> dataList,List<City> deptList){
deptList.forEach(city-> {
Tree<City> tree = new Tree<>();
tree.setId(city.getId().toString());
tree.setParentId(city.getParentId().toString());
tree.setText(city.getName());
dataList.add(tree);
});
}
小结
添加子节点的函数(递归算法部分)可以优化;Tree类型属性传值有待优化。