zoukankan      html  css  js  c++  java
  • java实现DAG广度优先便利

    在调度系统中经常可以看到有向无环图,假如我们用点表和边表来存储一个图,那么如何能实现按照优先级的排序呢?

    下面是我的一个实现:

    一、方案1

    子节点的优先级等于父节点的和?

    问题:虽然可以保证子节点一定大于等于父节点,但如果只有一个父节点,会导致父子优先级相同,因此否掉

    二、方案2

    子节点的优先级等于被指向的次数

    问题:被指向的次数多不代表优先级低,否掉

    三、方案3

    子节点优先级=父节点优先级的和,再加上被指向次数

    继承了方案1/2的优点,接下来看怎么实现?

    一开始想的是遍历边表,然后节点的优先级直接等于被指向次数+父节点优先级,发现有一个问题,父节点优先级后续有可能变化,但前面的子节点无法感知

    升级方案:

    1.先遍历边表,实现一个父节点的子节点map

    2.重新遍历边表,对被指向节点进行+1操作,之后递归遍历被指向节点的所有下游节点,统一进行+1操作,这样就实现了:

    在当前to节点+1时完成了被指向次数的初始化,

    递归子节点统一+1,完成了子节点=父节点优先级的求和操作。(上游节点自增时,下游都跟着自增,上游增多少,下游就增多少)

    public class GraphUtil {
        public static void main(String[] args) {
            Set<String> nodes = Sets.newHashSet("A", "B", "C", "D", "E", "F", "G");
            List<String> nodeList = Lists.newArrayList("G->E", "G->F", "E->D", "F->C","C->B", "C->A","B->A");
            List<Edge<String, String>> edges = nodeList.stream().map(str -> {
                String[] split = str.split("->");
                String from = split[0];
                String to = split[1];
                return new Edge<>(from, to);
            }).collect(Collectors.toList());
    
            Graph graph = new Graph(nodes, edges);
            Set<String> headNodes = findHeadNodes(graph);
            System.out.println(headNodes);
            Map<String, Integer> priority = findPriority(graph);
            System.out.println(priority);
        }
    
        /**
         * 解决方案1:
         * 通过计算被指向的次数,来计算节点的执行顺序
         * 问题:被指向的次数多,不一定优先级低!
         * 解决方案2:
         * 设置被指向节点优先级=所有父节点的和,保证子节点一定比父节点大
         * 问题:如果子节点只有一个父节点,子节点的优先级就会跟父节点相同!
         * 解决方案3:
         * 0.设置被指向节点优先级=所有父节点的和+被指向次数
         * 1.遍历边表,先生成一个父节点和子节点的映射map
         * 2.再次遍历边表,如果是头节点,默认值设0,如果是尾节点默认设0,已存在=节点原有值+1
         * 3.递归给尾节点的所有下游节点+1
         * 如此则避免了方案1、2的缺陷,保证子节点的优先级一定低于双亲节点
         *
         * @param graph
         * @return
         */
        public static Map<String, Integer> findPriority(Graph graph) {
            List<Edge<String, String>> edges = graph.getEdges();
            HashMultimap<String, String> childMap = HashMultimap.create();
            TreeMap<String, Integer> priorityMap = new TreeMap<>();
    
            for (Edge<String, String> s : edges) {
                String from = s.getStart();
                String to = s.getEnd();
                childMap.put(from, to);
            }
    
            System.out.println(childMap);
    
            for (Edge<String, String> s : edges) {
                String from = s.getStart();
                String to = s.getEnd();
                priorityMap.putIfAbsent(from, 0);
                priorityMap.putIfAbsent(to, 0);
                priorityMap.computeIfPresent(to, (k, v) -> v = v + 1);
                //不仅to自己更新,还要递归更新自己的下游节点
                updateChild(priorityMap, childMap, to);
            }
    
            return priorityMap;
        }
    
        /**
         * 只要某个节点+1,那么它后面的所有子节点都递归加1
         *
         * @param priorityMap
         * @param childMap
         * @param parent
         */
        public static void updateChild(TreeMap<String, Integer> priorityMap, HashMultimap<String, String> childMap, String parent) {
            if (childMap.containsKey(parent)) {
                Set<String> children = childMap.get(parent);
                for (String child : children) {
                    priorityMap.putIfAbsent(child, 0);
                    priorityMap.computeIfPresent(child, (k, v) -> v + 1);
                    if (childMap.containsKey(child)) {
                        updateChild(priorityMap, childMap, child);
                    }
                }
            }
        }
    
        /**
         * 查找头节点,可能不是一个
         *
         * @param graph
         * @return
         */
        public static Set<String> findHeadNodes(Graph graph) {
            List<Edge<String, String>> edges = graph.getEdges();
            Multimap<String, String> dependMap = HashMultimap.create();
            Map<String, Integer> priorityMap = new TreeMap<>();
            for (Edge<String, String> edge : edges) {
                String from = edge.getStart();
                String to = edge.getEnd();
                priorityMap.putIfAbsent(from, 0);
                priorityMap.putIfAbsent(to, 0);
                dependMap.put(to, from);
                priorityMap.computeIfPresent(to, (k, v) -> v = v + 1);
            }
    
            Set<String> set = Sets.newHashSet();
            for (Map.Entry<String, Integer> s : priorityMap.entrySet()) {
                if (s.getValue() == 0) {
                    set.add(s.getKey());
                }
            }
            return set;
        }
    
    
    }

    Graph类,Edge类

    /**
     * @Author : wangbin
     * @Date : 2021/9/28 14:36
     * @Description: 以边表和点表构成的有向无环图数据结构
     */
    @Data
    @AllArgsConstructor
    public class Graph {
        private Set<String> nodes;
        private List<Edge<String, String>> edges;
    }
    
    //======================================
    
    @Data
    @AllArgsConstructor
    public class Edge<S,E> {
        private S start;
        private E end;
    
    }

    输出:

    [G]
    {B=[A], C=[A, B], E=[D], F=[C], G=[E, F]}
    {A=7, B=3, C=2, D=2, E=1, F=1, G=0}

     补充:

    虽然得到了treeMap,但是它是以key进行排序,如果想按照value输出,还有进行处理
    /**
         * 获取以优先级顺序排序的<任务:优先级>list
         * @param graph
         * @return
         */
        public static List<Map.Entry<String, Integer>> getPriorityList(Graph graph) {
            TreeMap<String, Integer> priorityMap = findPriority(graph);
            List<Map.Entry<String, Integer>> entries = new ArrayList<>(priorityMap.entrySet());
            entries.sort(Map.Entry.comparingByValue());
            return entries;
        }
  • 相关阅读:
    Spring基础知识
    Hibernate基础知识
    Struts2基础知识
    在eclipse里头用checkstyle检查项目出现 File contains tab characters (this is the first instance)原因
    java后台获取cookie里面值得方法
    ckplayer 中的style.swf 中的 style.xml 中的修改方法
    java hql case when 的用法
    Windows下Mongodb安装及配置
    Mongodb中经常出现的错误(汇总)child process failed, exited with error number
    Mac 安装mongodb
  • 原文地址:https://www.cnblogs.com/wangbin2188/p/15350184.html
Copyright © 2011-2022 走看看