概要:
使用BFS(广度优先搜索)、DFS(深度优先搜索)的递归和非递归方式获取树深度。
代码:
Util类:
package com.example.study.util;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Stack;
import java.util.stream.Collectors;
/**
* 获取树深度
* 注:若最深一层只有null元素,该层不计入深度
*/
public class TreeDepthUtil {
private static final Byte FLAG = 1;
/**
* dfs的递归实现获取树深度
*
* @param root 根节点
* @param childField 子节点列表字段名称
* @param <T> 节点类型
* @return 树深度
*/
public static <T> int getTreeDepthByDfsWithRecursion(T root, String childField) {
if (root == null || !StringUtils.hasText(childField)) {
return 0;
}
List<Integer> depth = new ArrayList<>(1);
depth.add(0);
// 这里只是需要一个标志,表示当前路径上的点,所以用byte减少内存占用
Stack<Byte> stack = new Stack<>();
doGetTreeDepthByDfs(root, childField, stack, depth);
return depth.get(0);
}
private static <T> void doGetTreeDepthByDfs(T parent, String childField, Stack<Byte> stack, List<Integer> depth) {
stack.push(FLAG);
depth.set(0, Math.max(depth.get(0), stack.size()));
Collection<T> childs = (Collection<T>) getFieldValue(parent, childField);
if (CollectionUtils.isEmpty(childs)) {
stack.pop();
return;
}
for (T child : childs) {
if (child == null) {
continue;
}
doGetTreeDepthByDfs(child, childField, stack, depth);
}
stack.pop();
}
/**
* dfs的非递归(循环)实现获取树深度
*
* @param root 根节点
* @param childField 子节点列表字段名称
* @param <T> 节点类型
* @return 树深度
*/
public static <T> int getTreeDepthByDfsWithLoop(T root, String childField) {
if (root == null || !StringUtils.hasText(childField)) {
return 0;
}
Stack<Iterator> stack = new Stack<>();
List<T> list = new ArrayList<>();
list.add(root);
Iterator<T> iterator = list.iterator();
Iterator<T> emptyIterator = (Iterator<T>) Collections.emptyList().iterator();
int depth = 0;
while (true) {
while (!iterator.hasNext() && !stack.isEmpty()) {
iterator = stack.pop();
}
if (!iterator.hasNext() && stack.isEmpty()) {
break;
}
stack.push(iterator);
depth = Math.max(depth, stack.size());
T next = iterator.next();
Collection<T> childs = (Collection<T>) getFieldValue(next, childField);
if (childs != null) {
childs = childs.stream().filter(o -> o != null).collect(Collectors.toList());
}
iterator = childs == null ? emptyIterator : childs.iterator();
}
return depth;
}
/**
* bfs的递归实现获取树深度
*
* @param root 根节点
* @param childField 子节点列表字段名称
* @param <T> 节点类型
* @return 树深度
*/
public static <T> int getTreeDepthByBfsWithRecursion(T root, String childField) {
if (root == null || !StringUtils.hasText(childField)) {
return 0;
}
List<T> parents = new ArrayList<>();
parents.add(root);
List<Integer> depth = new ArrayList<>(1);
depth.add(0);
doGetTreeDepthByBfs(parents, childField, depth);
return depth.get(0);
}
private static <T> void doGetTreeDepthByBfs(Collection<T> parents, String childField, List<Integer> depth) {
if (parents.isEmpty()) {
return;
}
depth.set(0, depth.get(0) + 1);
readChilds(parents, childField);
doGetTreeDepthByBfs(parents, childField, depth);
}
/**
* bfs的非递归(循环)实现获取树深度
*
* @param root 根节点
* @param childField 子节点列表字段名称
* @param <T> 节点类型
* @return 树深度
*/
public static <T> int getTreeDepthByBfsWithLoop(T root, String childField) {
if (root == null || !StringUtils.hasText(childField)) {
return 0;
}
List<T> parents = new ArrayList<>();
parents.add(root);
int depth = 0;
while (!parents.isEmpty()) {
depth++;
readChilds(parents, childField);
}
return depth;
}
private static <T> void readChilds(Collection<T> parents, String childField) {
List<T> allChilds = new ArrayList<>();
for (T parent : parents) {
Collection<T> childs = (Collection<T>) getFieldValue(parent, childField);
if (childs == null) {
continue;
}
allChilds.addAll(childs.stream().filter(o -> o != null).collect(Collectors.toList()));
}
parents.clear();
parents.addAll(allChilds);
}
/**
* 获取字段值
*
* @param element 待获取值的对象
* @param fieldName 字段名称
* @param <T> 对象类型
* @return 字段值
*/
private static <T> Object getFieldValue(T element, String fieldName) {
try {
Field field = element.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(element);
} catch (IllegalAccessException exception) {
throw new RuntimeException("no permission to read field [" + fieldName + "]!");
} catch (NoSuchFieldException e) {
throw new RuntimeException("field [" + fieldName + "] not exists!");
}
}
}
测试;
部门信息类:
package com.example.study.entity;
import lombok.Data;
import java.util.List;
/**
* 部门实体类
*/
@Data
public class DepartmentEntity {
/**
* 部门id
*/
private Integer id;
/**
* 部门名称
*/
private String name;
/**
* 上级部门id
*/
private Integer parentId;
/**
* 子部门列表
*/
private List<DepartmentEntity> childs;
}
测试类:
package com.example.study.util;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.example.study.entity.DepartmentEntity;
import java.util.List;
public class Test {
public static void main(String[] args) {
String data = "[ { \"id\": 0, \"name\": \"部门0(根部门)\", \"parentId\": -1 }, { \"id\": 1, \"name\": \"部门1\", \"parentId\": 0 }, { \"id\": 2, \"name\": \"部门2\", \"parentId\": 0 }, { \"id\": 3, \"name\": \"部门3\", \"parentId\": 0 }, { \"id\": 4, \"name\": \"部门4\", \"parentId\": 2 }, { \"id\": 5, \"name\": \"部门5\", \"parentId\": 2 }, { \"id\": 6, \"name\": \"部门6\", \"parentId\": 3 }, { \"id\": 7, \"name\": \"部门7\", \"parentId\": 3 }, { \"id\": 8, \"name\": \"部门8\", \"parentId\": 6 }, { \"id\": 9, \"name\": \"部门9\", \"parentId\": 7 }, { \"id\": 10, \"name\": \"部门10\", \"parentId\": 9 }, { \"id\": 11, \"name\": \"部门11\", \"parentId\": 9 } ]";
List<DepartmentEntity> departments = JSONArray.parseArray(data, DepartmentEntity.class);
DepartmentEntity root = departments.stream().filter(o -> o.getParentId() == -1).findFirst().get();
ListTreeConvertUtil.listToTree(departments, root, "parentId", "id", "childs");
System.out.println(JSON.toJSONString(root));
DepartmentEntity tmp = new DepartmentEntity();
root.getChilds().add(1, null);
root.getChilds().get(3).getChilds().get(0).getChilds().get(0).setChilds(null);
root.getChilds().get(3).getChilds().get(1).getChilds().get(0).getChilds().get(1).getChilds().add(null);
root.getChilds().get(3).getChilds().get(1).getChilds().get(0).getChilds().get(1).getChilds().add(tmp);
System.out.println(JSON.toJSONString(root));
System.out.println(TreeDepthUtil.getTreeDepthByDfsWithRecursion(root, "childs"));
System.out.println(TreeDepthUtil.getTreeDepthByDfsWithLoop(root, "childs"));
System.out.println(TreeDepthUtil.getTreeDepthByBfsWithRecursion(root, "childs"));
System.out.println(TreeDepthUtil.getTreeDepthByBfsWithLoop(root, "childs"));
}
}
测试结果:
{"childs":[{"childs":[],"id":1,"name":"部门1","parentId":0},{"childs":[{"childs":[],"id":4,"name":"部门4","parentId":2},{"childs":[],"id":5,"name":"部门5","parentId":2}],"id":2,"name":"部门2","parentId":0},{"childs":[{"childs":[{"childs":[],"id":8,"name":"部门8","parentId":6}],"id":6,"name":"部门6","parentId":3},{"childs":[{"childs":[{"childs":[],"id":10,"name":"部门10","parentId":9},{"childs":[],"id":11,"name":"部门11","parentId":9}],"id":9,"name":"部门9","parentId":7}],"id":7,"name":"部门7","parentId":3}],"id":3,"name":"部门3","parentId":0}],"id":0,"name":"部门0(根部门)","parentId":-1}
{"childs":[{"childs":[],"id":1,"name":"部门1","parentId":0},null,{"childs":[{"childs":[],"id":4,"name":"部门4","parentId":2},{"childs":[],"id":5,"name":"部门5","parentId":2}],"id":2,"name":"部门2","parentId":0},{"childs":[{"childs":[{"id":8,"name":"部门8","parentId":6}],"id":6,"name":"部门6","parentId":3},{"childs":[{"childs":[{"childs":[],"id":10,"name":"部门10","parentId":9},{"childs":[null,{}],"id":11,"name":"部门11","parentId":9}],"id":9,"name":"部门9","parentId":7}],"id":7,"name":"部门7","parentId":3}],"id":3,"name":"部门3","parentId":0}],"id":0,"name":"部门0(根部门)","parentId":-1}
6
6
6
6