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两者是如何关联成一个树呢?
引用的原因:当遍历二级节点查询并添加所有下级三级节点时,相应一级节点下对应的二级节点也会改变,即也会有上边的三级节点。

image
image

耗时比较

类型 响应耗时 时间复杂度
直接查询数据库 415ms、407ms、410ms
方式一 47ms、46ms、53ms O(n平方)
方式二 16ms、16ms、15ms O(n)

参考链接

链接一

链接二

posted @ 2022-01-17 22:04  永无八哥  阅读(697)  评论(0编辑  收藏  举报