美文网首页
将数据构建为树结构

将数据构建为树结构

作者: 帮我的鸵鸟盖个章 | 来源:发表于2018-12-27 16:46 被阅读0次

    树形结构就是有层级关系的数据结构。

    可以解释为:

    所有数据构成一颗大树,这颗大树又是由十颗小树组成的;

    这十颗小树的层级为1,并且是排序的,其pId是0,pId是自身与上一颗树的关联,0表示顶层,其值必须为唯一字段

    其中每一颗小树又是由另外若干小小树组成,小小树层级为2,并且是排序的,其pId是它上一级(小树)的id

    依次类推,就形成了一整颗数。

    要想构建一棵树,必须有以下字段:

    • level :层级
    • sort :排序
    • pId :上一级的id
    • path :path表示为该树在一整颗数上的路径。
      • eg:A下面有B,B下面有C和D,假如path构成规则为:以id构成path,并且以/隔开,那么D的path为:/id-a/id-b/id-d/
      • path的构成规则及其重要,实际项目中需根据需求灵活使用,可以为id或者其他字段,方便查询。最后构成的path必须唯一
    • rootId :其实rootId并不是必须的,但是在实际使用中发现,加入这个字段以后,可以简化很多代码!这个字段记录的是root树的唯一标识id,在分页和查询中十分好用。

    展示类似于下图

    树结构.png

    其中有笑gfff笑,哈哈呵呵三棵树,展开哈哈,发现有三层。

    在Java中,构建一个实体类A的DTO,继承A实现轮子中的方法,增加children属性用来存放子级

    构建树的轮子:

    public class TreeUtils<T extends TreeUtils.Tree> {
    
        /**
         * 只是适用于按顺序目录结构排好序的查询方式
         *
         * @param objects  查询的全部目录(平行结构),按path降序排序
         * @param maxLevel 最大层级
         * @return
         */
        public List<T> createTree(List<T> objects, Integer maxLevel) {
            //List必须是根据codePath倒序查询得出;
            Map<Integer, List<T>> map = new HashMap<>();
            for (int i = 0; i < maxLevel; i++) {//构造层级容器
                map.put(i + 1, new ArrayList<T>());
            }
            Integer tempLevel = maxLevel + 1;//构造临时层级,为了开个头
            for (T current : objects) {
                Integer currentLv = current.getLevel();
                if (currentLv < tempLevel) {//当前层级小于临时层级
                    List<T> children = map.get(currentLv + 1);//先拿子节点
                    current.setChildren(children);//将子节点并入所在层级集合
                    map.put(currentLv + 1, new ArrayList<T>());//然后清空子节点
                }
                map.get(currentLv).add(current);//将自己并入所在层级集合
                map.get(currentLv).sort((a, b) -> a.getSort() - b.getSort());//排序
                tempLevel = currentLv;//重新构造层级
            }
            List<T> list = map.get(1);
            return list;
        }
    
        /**
         * 只适用于从根节点一次清查询出来的list,不需要排好序
         *
         * @param objects
         * @return
         */
        public List<T> createTree(List<T> objects) {
            return createTree(objects, 1, "0");
        }
    
        /**
         * 适用于从某个节点一次清查询出来的list,不需要排好序
         *
         * @param objects
         * @return
         */
        public List<T> createTree(List<T> objects, Integer startLevel, String pid) {
            Map<Integer, Map<String, List<T>>> levelMap = new HashedMap();//保存某一级的map结构 map<三级,map<pid,子目录>>
            for (T t : objects) {
                Integer currentLevel = t.getLevel();//当前层级
                if (levelMap.get(currentLevel) == null) {
                    levelMap.put(currentLevel, new HashMap<>());
                }
                if (levelMap.get(currentLevel).get(t.getpId()) == null) {
                    levelMap.get(currentLevel).put(t.getpId(), new ArrayList<T>());
                }
                levelMap.get(currentLevel).get(t.getpId()).add(t);
            }
            List<T> roots = levelMap.get(startLevel).get(pid);
            roots.forEach(a -> addChildren(a, levelMap));
            roots.sort((a, b) -> a.getSort() - b.getSort());
            return roots;
        }
    
        void addChildren(T t, Map<Integer, Map<String, List<T>>> levelMap) {
            Map<String, List<T>> chidrenMap = levelMap.get(t.getLevel() + 1);
            if (chidrenMap != null) {
                List<T> children = chidrenMap.get(t.getId());
                if (children != null) {
                    children.forEach((child) -> addChildren(child, levelMap));
                    children.sort((a, b) -> a.getSort() - b.getSort());
                    t.setChildren(children);
                }
            }
            return;
        }
    
        public interface Tree<T extends TreeUtils.Tree> {
            String getId();
    
            Integer getSort();
    
            String getpId();
    
            Integer getLevel();
    
    //        String getPath();
    
            List<T> getChildren();
    
            void setChildren(List<T> childrenList);
        }
    
        /**
         * 只是适用于按顺序目录结构排好序的查询方式
         * 如没子集一律返回空集合
         *
         * @param objects  查询的全部目录(平行结构),按path降序排序
         * @param maxLevel 最大层级
         * @return
         */
        public List<T> createTrees(List<T> objects, Integer maxLevel) {
            //List必须是根据codePath倒序查询得出;
            Map<Integer, List<T>> map = new HashMap<>();
            for (int i = 0; i < maxLevel; i++) {//构造层级容器
                map.put(i + 1, new ArrayList<T>());
            }
            Integer tempLevel = maxLevel + 1;//构造临时层级,为了开个头
            for (T current : objects) {
                Integer currentLv = current.getLevel();
                if (currentLv < tempLevel) {//当前层级小于临时层级
                    List<T> children = map.get(currentLv + 1);//先拿子节点
                    if (children == null) {
                        children = new ArrayList<>();
                    }
                    current.setChildren(children);//将子节点并入所在层级集合
                    map.put(currentLv + 1, new ArrayList<T>());//然后清空子节点
                }
                map.get(currentLv).add(current);//将自己并入所在层级集合
                map.get(currentLv).sort((a, b) -> a.getSort() - b.getSort());//排序
                tempLevel = currentLv;//重新构造层级
            }
            List<T> list = map.get(1);
            return list;
        }
    
    
    }
    
    

    实体类:

    public class EpcSystemDictionary extends SuperEntity{
        private String id;
        private Date createTime;
        private Date updateTime;
        private String code; //编号
        private String name; //名称
        private Integer sort;//排序
        private String pId;//父id
        private String enName;
        private Integer isDelete;
        private Integer level;//层级
        private String path;
    
        public EpcSystemDictionary() {
        }
    
        public EpcSystemDictionary(String id, String code, String name,String enName, Integer sort, String pId, Integer level, String path) {
            this.id = id;
            this.code = code;
            this.name = name;
            this.enName=enName;
            this.sort = sort;
            this.pId = pId;
            this.level = level;
            this.path = path;
        }
    
        public String getId() {
            return id;
        }
    
        public void setId(String id) {
            this.id = id;
        }
    
        public Date getCreateTime() {
            return createTime;
        }
    
        public void setCreateTime(Date createTime) {
            this.createTime = createTime;
        }
    
        public Date getUpdateTime() {
            return updateTime;
        }
    
        public void setUpdateTime(Date updateTime) {
            this.updateTime = updateTime;
        }
    
        public String getCode() {
            return code;
        }
    
        public void setCode(String code) {
            this.code = code;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Integer getSort() {
            return sort;
        }
    
        public void setSort(Integer sort) {
            this.sort = sort;
        }
    
        public String getpId() {
            return pId;
        }
    
        public void setpId(String pId) {
            this.pId = pId;
        }
    
        public String getEnName() {
            return enName;
        }
    
        public void setEnName(String enName) {
            this.enName = enName;
        }
    
        public Integer getIsDelete() {
            return isDelete;
        }
    
        public void setIsDelete(Integer isDelete) {
            this.isDelete = isDelete;
        }
    
        public Integer getLevel() {
            return level;
        }
    
        public void setLevel(Integer level) {
            this.level = level;
        }
    
        public String getPath() {
            return path;
        }
    
        public void setPath(String path) {
            this.path = path;
        }
    }
    
    

    DTO:

    public class EpcSystemDictionaryDto extends EpcSystemDictionary implements TreeUtils.Tree<EpcSystemDictionaryDto> {
    
        List<EpcSystemDictionaryDto> children = new ArrayList<>();
    
        @Override
        public List<EpcSystemDictionaryDto> getChildren() {
            return children;
        }
    
        @Override
        public void setChildren(List<EpcSystemDictionaryDto> childrenList) {
            this.children=childrenList;
        }
    
    }
    
    

    调用:

    /**
         * 获取字典某一个根列表
         *
         * @param
         * @return
         */
        @Override
        public EpcSystemDictionaryDto getOneRoot(String name, Long companyId) {
            //避免写接口地址的时候传入的name后面没有写“/”
            name = name.length() == (name.lastIndexOf("/") + 1) ? name : name + "/";
            List<EpcSystemDictionaryDto> epcSystemDictionaryList = epcSystemDictionaryMapper.selectOneRoot(name, companyId);
            for (EpcSystemDictionaryDto e : epcSystemDictionaryList) {
                if (e.getPath().equals(name)) {
                    return new TreeUtils<EpcSystemDictionaryDto>().createTree(epcSystemDictionaryList, e.getLevel(), e.getpId()).get(0);
                }
            }
            return new EpcSystemDictionaryDto();
        }
    

    代码其实不难,难的是操作数据的思想,对数据结构变化的把握,通过数据的现时情况得到自己想要的结果。

    路漫漫其修远兮,吾将上下而求索。

    相关文章

      网友评论

          本文标题:将数据构建为树结构

          本文链接:https://www.haomeiwen.com/subject/qlcdlqtx.html