list转tree两种方法
TreeVO类
import java.util.List;
public class TreeVO {
String id;
String name;
String parentId;
List<TreeVO> children;
public TreeVO(String id, String name, String parentId) {
this.id = id;
this.name = name;
this.parentId = parentId;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getParentId() {
return parentId;
}
public void setParentId(String parentId) {
this.parentId = parentId;
}
public List<TreeVO> getChildren() {
return children;
}
public void setChildren(List<TreeVO> children) {
this.children = children;
}
@Override
public String toString() {
return "Zone{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", parentId='" + parentId + '\'' +
", children=" + children +
'}';
}
}
TreeUtil类
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @Description:
* @Author party-abu
* @Date 2022/1/17 14:37
*/
public class TreeUtils {
/**
* 方式一
* 时间复杂度是O(n平方)
*
* @param zoneList 需要转化为tree的list
* @param topParentId 根节点的父id
* @return
*/
public static List<TreeVO> buildTree01(List<TreeVO> zoneList, String topParentId) {
List<TreeVO> result = new ArrayList<>();
// 第一次遍历
for (TreeVO treeVO : zoneList) {
// 找到并添加所有根节点
if (treeVO.getParentId().equals(topParentId)) {
result.add(treeVO);
}
// 帮助找到遍历到的当前节点的所有下一级子节点,并将所有的下一级节点添加到当前节点的children列表中
for (TreeVO childrenZone : zoneList) {
if (childrenZone.getParentId().equals(treeVO.id)) {
if (treeVO.getChildren() == null) {
treeVO.children = new ArrayList<>();
}
treeVO.getChildren().add(childrenZone);
}
}
}
return result;
}
/**
* 方式二 推荐使用
* 时间复杂度是O(n)
*
* @param zoneList
* @param topParentId
* @return
*/
public static List<TreeVO> buildTree02(List<TreeVO> zoneList, String topParentId) {
Map<String, List<TreeVO>> zoneByParentIdMap = new HashMap<>();
// 将parentId相同的Zone放在同一个列表中,parentId作为key
for (TreeVO treeVO : zoneList) {
List<TreeVO> children = zoneByParentIdMap.getOrDefault(treeVO.parentId, new ArrayList<>());
children.add(treeVO);
zoneByParentIdMap.put(treeVO.parentId, children);
}
// 从map中查询当前节点所有的子节点,并放在当前节点的children列表中
for (TreeVO treeVO : zoneList) {
treeVO.children = zoneByParentIdMap.get(treeVO.id);
}
// 过滤出顶级菜单列表
return zoneList.stream()
.filter(treeVO -> treeVO.parentId.equals(topParentId))
.collect(Collectors.toList());
}
}
测试类
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String[] args) {
List<TreeVO> zoneList = new ArrayList<>();
zoneList.add(new TreeVO("1", "上海", "0"));
zoneList.add(new TreeVO("2", "北京", "0"));
zoneList.add(new TreeVO("3", "河南", "0"));
zoneList.add(new TreeVO("11", "松江", "1"));
zoneList.add(new TreeVO("31", "郑州", "3"));
zoneList.add(new TreeVO("32", "洛阳", "3"));
zoneList.add(new TreeVO("111", "泗泾", "11"));
zoneList.add(new TreeVO("321", "洛龙", "32"));
List<TreeVO> tree01 = TreeUtils.buildTree01(zoneList, "0");
List<TreeVO> tree02 = TreeUtils.buildTree02(zoneList, "0");
}
}
方式一
/**
* 方式一
* 时间复杂度是O(n平方)
*
* @param zoneList 需要转化为tree的list
* @param topParentId 根节点的父id
* @return
*/
public static List<TreeVO> buildTree01(List<TreeVO> zoneList, String topParentId) {
List<TreeVO> result = new ArrayList<>();
// 第一次遍历
for (TreeVO treeVO : zoneList) {
// 找到并添加所有根节点
if (treeVO.getParentId().equals(topParentId)) {
result.add(treeVO);
}
// 帮助找到遍历到的当前节点的所有下一级子节点,并将所有的下一级节点添加到当前节点的children列表中
for (TreeVO childrenZone : zoneList) {
if (childrenZone.getParentId().equals(treeVO.id)) {
if (treeVO.getChildren() == null) {
treeVO.children = new ArrayList<>();
}
treeVO.getChildren().add(childrenZone);
}
}
}
return result;
}
方式二
/**
* 推荐使用
* 时间复杂度是O(n)
*
* @param zoneList
* @param topParentId
* @return
*/
public static List<TreeVO> buildTree02(List<TreeVO> zoneList, String topParentId) {
Map<String, List<TreeVO>> zoneByParentIdMap = new HashMap<>();
// 将parentId相同的Zone放在同一个列表中,parentId作为key
for (TreeVO treeVO : zoneList) {
List<TreeVO> children = zoneByParentIdMap.getOrDefault(treeVO.parentId, new ArrayList<>());
children.add(treeVO);
zoneByParentIdMap.put(treeVO.parentId, children);
}
// 从map中查询当前节点所有的子节点,并放在当前节点的children列表中
for (TreeVO treeVO : zoneList) {
treeVO.children = zoneByParentIdMap.get(treeVO.id);
}
// 过滤出顶级菜单列表
return zoneList.stream()
.filter(treeVO -> treeVO.parentId.equals(topParentId))
.collect(Collectors.toList());
}
方式二增强版
/**
* 使用stream的两次遍历
*
* @param zoneList
* @param topParentId
* @return
*/
public static List<ResourceTreeVO> createTree03(List<ResourceTreeVO> zoneList, Integer topParentId) {
long beginTime = System.nanoTime();
// 将parentId相同的Zone放在同一个列表中,parentId作为key
Map<Integer, List<ResourceTreeVO>> zoneByParentIdMap =
zoneList.stream()
.collect(Collectors.groupingBy(ResourceTreeVO::getParentId));
// 从map中查询当前节点所有的子节点,并放在当前节点的children列表中
for (ResourceTreeVO zone : zoneList) {
zone.setResourceTreeList(zoneByParentIdMap.get(zone.getResourceId()));
}
// 过滤出顶级菜单列表
List<ResourceTreeVO> ResourceTreeVOList = zoneList.stream()
.filter(zone -> zone.getParentId().equals(topParentId))
.collect(Collectors.toList());
long endTime = System.nanoTime();
System.out.println("createResourceTreeVO03 = " + (endTime - beginTime));
return ResourceTreeVOList;
}
对方式一理解
1.当遍历到顶级节点时,可以查到顶级节点所有的二级节点;
2.当遍历到二级节点时,可以查到二级节点所有的三级节点;
思考:1.2两者是如何关联成一个树呢?
引用的原因:当遍历二级节点查询并添加所有下级三级节点时,相应一级节点下对应的二级节点也会改变,即也会有上边的三级节点。
耗时比较
类型 | 响应耗时 | 时间复杂度 |
---|---|---|
直接查询数据库 | 415ms、407ms、410ms | |
方式一 | 47ms、46ms、53ms | O(n平方) |
方式二 | 16ms、16ms、15ms | O(n) |