美文网首页
成环检测和树型工具代码(四)

成环检测和树型工具代码(四)

作者: 旺叔叔 | 来源:发表于2019-03-13 17:58 被阅读0次

TreeNodeUtil工具

几处改进:
1.与其在插入树型结构时候遍历树型结构,不如用hashMap将已经放入树型结构的数据存起来。可直接取到。
并且有了拓扑排序的下标顺序数组,可一次完成。
2.ID改为通用类型
3.增加了parentId合法性检测

public class TreeNodeUtil<T, K extends Comparable> {
private static final String DATA_FIELD = "data";
private static final String CHILDREN_FIELD = "children";
/**
 * 根据list集合生成树形结构返回
 * @param list 集合
 * @param idField 自身id字段名
 * @param parentIdField 父对象id字段名
 * @return 树型结构集合
 */
public List<Map<String, Object>> generateTree(List<T> list, String idField, String parentIdField) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
    List<Map<String, Object>> resultList = new LinkedList<>();
    /**
     * 空集合直接返回结果
     */
    if(null == list || 0 == list.size())
        return resultList;

    int[] indexList = new TopologicalSortUtil<T, K>().ringCheck(list, idField, parentIdField);
    /**
     * 空结果或者成环 上方判断了空结果这里只可能是成环
     */
    if(0 == indexList.length){
        throw new RuntimeException("结果集成环,无法拼接成树形结构");
    }
    /**
     * 反射获取获得相应ID的方法
     */
    Class<?> clazz = list.get(0).getClass();
    Method getSelfIdMethod = clazz.getMethod("get" + idField.substring(0, 1).toUpperCase() + idField.substring(1));
    Method getParentIdMethod = clazz.getMethod("get" + parentIdField.substring(0, 1).toUpperCase() + parentIdField.substring(1));
    /**
     * 先将parent字段为空的节点放入最终树型集合
     */
    Map<K, Map<String, Object>> map = new HashMap<>();
    for (T node : list) {
        if (null == getParentIdMethod.invoke(node)) {
            Map<String, Object> nodeMap = new HashMap<>();
            nodeMap.put(DATA_FIELD, node);
            resultList.add(nodeMap);
            map.put((K) getSelfIdMethod.invoke(node), nodeMap);
        }
    }
    /**
     * 拓扑排序后的结果可一次遍历全部放入
     */
    for (int i = 0; i < indexList.length; ++i) {
        T node = list.get(indexList[i]);
        K parentId = (K)getParentIdMethod.invoke(node);
        if(null == parentId) {
            continue;
        }
        Map<String, Object> root = map.get(getParentIdMethod.invoke(node));
        if(null == root.get(CHILDREN_FIELD)){
            root.put(CHILDREN_FIELD, new LinkedList<>());
        }
        Map<String, Object> child = new HashMap<>();
        child.put(DATA_FIELD, node);
        List<Object> children = (List<Object>)root.get(CHILDREN_FIELD);
        children.add(child);
        map.put((K)getSelfIdMethod.invoke(node), child);
    }

    return resultList;
}}

TopologicalSortUtil工具

public class TopologicalSortUtil<T, K extends Comparable> {
/**
 * 拓扑排序
 * @param list 集合
 * @param idField 自身id字段名
 * @param parentIdField 父对象id字段名
 * @return 可执行的下标数组
 */
public int[] ringCheck(List<T> list, String idField, String parentIdField) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
    /**
     * 空集合当做无环处理
     */
    if(null == list || 0 == list.size())
        return new int[]{};

    /**
     * 反射获取获得相应ID的方法
     */
    Class<?> clazz = list.get(0).getClass();
    Method getSelfIdMethod = clazz.getMethod("get" + idField.substring(0, 1).toUpperCase() + idField.substring(1));
    Method getParentIdMethod = clazz.getMethod("get" + parentIdField.substring(0, 1).toUpperCase() + parentIdField.substring(1));
    Map<K, Integer> nodeIndexMap = new HashMap<>();
    int relationCount = 0;
    /**
     * 生成id与下标对应的map 用于下方转换成下标数组关系使用
     * 通常list为mybatis查询出的结合 是ArrayList get效率高
     */
    for (int index = 0; index < list.size(); index++) {
        K parentId = (K)getParentIdMethod.invoke(list.get(index));
        K id = (K)getSelfIdMethod.invoke(list.get(index));
        nodeIndexMap.put(id, index);
        if(null != parentId){
            relationCount++;
        }
    }
    /**
     * 将list中的关系翻译成[0,1](0为子,1为父)这样的数组 parentList
     */
    int [][] parentList = new int[relationCount][];
    int index = 0;
    for (Object node : list) {
        if(null != getParentIdMethod.invoke(node)){
            int[] parent = new int[2];
            K id = (K)getSelfIdMethod.invoke(node);
            K parentId = (K)getParentIdMethod.invoke(node);
            parent[0] = nodeIndexMap.get(id);
            if(null == nodeIndexMap.get(parentId))
                throw new RuntimeException("无效的parentId:" + parentId);
            parent[1] = nodeIndexMap.get(parentId);
            parentList[index++] = parent;
        }
    }

    return findOrder(list.size(), parentList);
}

/**
 * 拓扑排序生成可执行顺序
 */
public int[] findOrder(int numCourses, int[][] prerequisites) {
    List<List<Integer>> graph = new ArrayList<>();
    int[] res = new int[numCourses];
    int index = 0;
    int[] in = new int[numCourses];
    for (int i = 0; i < numCourses; i++) {
        graph.add(new ArrayList<>());
    }
    for (int[] edge : prerequisites) {
        graph.get(edge[1]).add(edge[0]);
        in[edge[0]]++;
    }

    Queue<Integer> queue = new LinkedList<>();
    for (int i = 0; i < numCourses; i++) {
        if (in[i] == 0) {
            queue.add(i);
            res[index++] = i;
        }
    }

    while(!queue.isEmpty()) {
        int i = queue.poll();
        for (int a : graph.get(i)) {
            in[a]--;
            if (in[a] == 0) {
                queue.add(a);
                res[index++] = a;
            }
        }

    }

    return index == numCourses ? res : new int[]{};
}}

相关文章

  • 成环检测和树型工具代码(四)

    TreeNodeUtil工具 TopologicalSortUtil工具

  • 有向图成环检测(三)

    如上文所述,显然当数据成环时候我们无论如何也无法将数据从列表变为树型返回。那么对列表数据进行成环检测便成了必要的数...

  • PHP检测代码的有效长度筛选注释行数

    写一个代码检测工具,检测代码的有效长度 读文件 检测每行

  • vue源码目录设计

    compiler 包含vue.js所有编译相关代码。包括把模版解析成ast树,ast语法树优化,代码生成等工具。 ...

  • 2018-10-25

    环(镯)型翡翠饰品的“音”与“质” 1、前言 通过上千件环(镯)型翡翠饰品(以下简称“翡翠饰品”)的检测,发现翡翠...

  • 强制执行Lint规范代码

    Lint 开发中使用静态代码检测工具对代码进行检查,达到规范代码减少bug的目的。常用的检测工具有FindBugs...

  • 百臂巨人与塔尔塔罗斯

    前言 一款静态代码检测工具,包含阿里java规约检测和lint检测,支持自定义pmd和lint配置,结合git在代...

  • Android 最佳实践のGralde插件开发

    前言 最近忙于开发代码检测工具,保证公司项目代码规范,所以研究起了代码检测插件,包括了CheckStyle、Fin...

  • 第一章 计算机网络概论

    1.网络的拓扑结构: 星型、环型,树型,全链接型,总线型,不规则型 2.可以按照互连的规模和通信方式,可以把网络分...

  • ESLint 的使用和.eslintrc.js配置

    在团队协作中,为避免低级 Bug、产出风格统一的代码,会预先制定编码规范。使用 Lint 工具和代码风格检测工具,...

网友评论

      本文标题:成环检测和树型工具代码(四)

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