任务DAG遍历,拓扑排序

0、定义

DAG:有向无环图

根据定义,可以得到以下两个结论:

  1. 如果图G中存在环(即G不是有向无环图),那么G不存在拓扑排序,反之如果G存在拓扑排序,则G中没有环
  2. 如果G是有向无环图,那么他的拓扑排序可能不止一种
  3. 拓扑排序的图,一定是有向无环图
  4. 有向无环图,一定能拓扑排序

1、分页遍历所有任务,同时根据任务的依赖关系,生成dag图

@Data
public class TaskDagGraphBO {
    private Set<Long> nodes = new HashSet<>();
    private List<TaskDagEdge> edges = new ArrayList<>();

    public TaskDagGraphBO() {
    }

    public TaskDagGraphBO(Long nodesSize) {
        this.nodes = new HashSet<>(Integer.parseInt(nodesSize+""));
    }

    public void addNode(Long node) {
        if(!this.nodes.contains(node)){
            this.nodes.add(node);
        }
    }

    public void addNodes(List<Long> nodes) {
        this.nodes.addAll(nodes);
    }

    public void addEdge(Long from, Long to) {
        Optional<TaskDagEdge> any = this.edges.stream().filter(e -> e.getFrom().equals(from) && e.getTo().equals(to)).findAny();
        if(!any.isPresent()){
            TaskDagEdge taskDagEdge = new TaskDagEdge(from, to);
            this.edges.add(taskDagEdge);
        }
    }

    public void remove(Long node) {
        this.nodes.remove(node);
        edges.removeIf(taskDagEdge -> taskDagEdge.getFrom().equals(node) || taskDagEdge.getTo().equals(node));
    }
}
public class TaskDagEdge{
    Long from;
    Long to;

    public TaskDagEdge(java.lang.Long start, java.lang.Long end) {
        this.from = start;
        this.to = end;
    }

    public Long getFrom() {
        return (Long) from;
    }

    public void setFrom(Long from) {
        this.from = from;
    }

    public Long getTo() {
        return (Long) to;
    }

    public void setTo(Long to) {
        this.to = to;
    }
}

使用:先添加所有节点,再添加边

 taskDagGraphBO.addNode(info.getTaskBasicInfo().getId());

 // 根据task依赖生成边
 taskDagGraphBO.addEdge(t.getTaskId(), info.getTaskBasicInfo().getId());

2、排序(广度优先)

  • 从 DAG 图中选择入度为的顶点(即没有节点指向该节点)并输出。
  • 从图中删除这个节点以及由他发出的有向边,同时针对该节点指向的子节点的入度减一。
  • 重复第一步和第二步,直到当前的 DAG 图为空或当前图中不存在无前驱的顶点为止。
  • 代码需要优化点为:第2步中,子节点入度减一时,不需要重新计算所有节点入度
  • 存在环判断:节点数不相等时
@Slf4j
public class TaskDAGUtil {

    public static List<Long> findPriority1(TaskDagGraphBO graph) {
        long start = System.nanoTime();
        int size = graph.getNodes().size();

        List<Long> res = new ArrayList<>();
        Queue<Long> queue = new LinkedList<>();
        Map<Long, Integer> inDegree = getInDegree(graph);

        inDegree.forEach((k,v)->{
            if(v.equals(0)){
                queue.add(k);
            }
        });

        while (!queue.isEmpty()) {
            Long cur = queue.poll();
            res.add(cur);

            graph.remove(cur);
            inDegree = getInDegree(graph);
            inDegree.forEach((k,v)->{
                if(v.equals(0)){
                    if(!queue.contains(k)) {
                        queue.add(k);
                    }
                }
            });
        }
        log.info("taskmigrete.taskdag.sort.time:{}inDegree:{}",System.nanoTime()-start,inDegree);

        // 若排序后节点小于 n,说明存在环
        return res.size() == size ? res : null;
    }

    /**
     * 始终寻找入度为0的点,直到所有节点加入结果队列
     *
     * @param graph
     * @return
     */
    public static List<Long> findPriority(TaskDagGraphBO graph) {
        List<Long> list = new ArrayList<>();
        Set<Long> nodes = graph.getNodes();
        Map<Long, Integer> inDegree = getInDegree(graph);
        int size = nodes.size();
        int count = 0;
        while (count < size && inDegree.keySet().size() != 0) {
            log.info("Finding priority:{}");
            for (Map.Entry<Long, Integer> entry : inDegree.entrySet()) {
                log.info("Finding inDegree iterator:{}",entry);
                Long key = entry.getKey();
                if (entry.getValue() == 0) {
                    list.add(key);
                    count++;
                    graph.remove(key);
                    inDegree = getInDegree(graph);
                }
            }
        }
        return list;
    }

    /**
     * 获取图中节点的入度
     *
     * @param graph
     * @return
     */
    public static Map<Long, Integer> getInDegree(TaskDagGraphBO graph) {
        Set<Long> nodes = graph.getNodes();
        List<TaskDagEdge> connectTable = graph.getEdges();
        Map<Long, Integer> map = new ConcurrentHashMap<>();
        for (Long node : nodes) {
            map.put(node, 0);
        }

        for (TaskDagEdge taskDagEdge : connectTable) {
            map.computeIfPresent(taskDagEdge.getTo(), (k, v) -> v + 1);
        }
        log.info("Finding inDegree:{}",map);
        return map;
    }

    public static void main(String[] args) {
        String s = "{\n" +
                "\t\"edges\": [{\n" +
                "\t\t\"from\": 1631269768021229570,\n" +
                "\t\t\"to\": 1651533478953267521\n" +
                "\t}, {\n" +
                "\t\t\"from\": 1655549249384906369,\n" +
                "\t\t\"to\": 1651533478953267521\n" +
                "\t}, {\n" +
                "\t\t\"from\": 1656941044568217217,\n" +
                "\t\t\"to\": 1656941044568184449\n" +
                "\t}, {\n" +
                "\t\t\"from\": 1656941044568209025,\n" +
                "\t\t\"to\": 1656941044568184449\n" +
                "\t}, {\n" +
                "\t\t\"from\": 1656941044568331905,\n" +
                "\t\t\"to\": 1656941044568184449\n" +
                "\t}, {\n" +
                "\t\t\"from\": 1656941044568217217,\n" +
                "\t\t\"to\": 1656941044568200833\n" +
                "\t}, {\n" +
                "\t\t\"from\": 1656941044568217217,\n" +
                "\t\t\"to\": 1656941044568209025\n" +
                "\t}, {\n" +
                "\t\t\"from\": 1656941044568200833,\n" +
                "\t\t\"to\": 1656941044568209025\n" +
                "\t}, {\n" +
                "\t\t\"from\": 1656941044568200833,\n" +
                "\t\t\"to\": 1656941044568331905\n" +
                "\t}],\n" +
                "\t\"nodes\": [1656941044568331905, 1628668617357041665, 1628655409208832002, 1656941044568184449, 1656941044568192641, 1656941044568200833, 1656941044568209025, 1656941044568217217, 1631269768021229570, 1655772785192377409, 1631476828683976706, 1651533478953267521, 1627858007982931970, 1655549249384906369]\n" +
                "}";

        String ege = "[{\n" +
                "\t\t\"from\": 1631269768021229570,\n" +
                "\t\t\"to\": 1651533478953267521\n" +
                "\t}, {\n" +
                "\t\t\"from\": 1655549249384906369,\n" +
                "\t\t\"to\": 1651533478953267521\n" +
                "\t}, {\n" +
                "\t\t\"from\": 1656941044568217217,\n" +
                "\t\t\"to\": 1656941044568184449\n" +
                "\t}, {\n" +
                "\t\t\"from\": 1656941044568209025,\n" +
                "\t\t\"to\": 1656941044568184449\n" +
                "\t}, {\n" +
                "\t\t\"from\": 1656941044568331905,\n" +
                "\t\t\"to\": 1656941044568184449\n" +
                "\t}, {\n" +
                "\t\t\"from\": 1656941044568217217,\n" +
                "\t\t\"to\": 1656941044568200833\n" +
                "\t}, {\n" +
                "\t\t\"from\": 1656941044568217217,\n" +
                "\t\t\"to\": 1656941044568209025\n" +
                "\t}, {\n" +
                "\t\t\"from\": 1656941044568200833,\n" +
                "\t\t\"to\": 1656941044568209025\n" +
                "\t}, {\n" +
                "\t\t\"from\": 1656941044568200833,\n" +
                "\t\t\"to\": 1656941044568331905\n" +
                "\t}]";
        JSONArray objects = JSONArray.parseArray(ege);
        List<TaskDagEdge> taskDagEdges = new ArrayList<>(objects.size());

        for(int i=0;i<objects.size();i++){
            JSONObject cur = objects.getJSONObject(i);
            TaskDagEdge e = new TaskDagEdge((Long)cur.get("from"),(Long)cur.get("to"));
            taskDagEdges.add(e);
        }

        TaskDagGraphBO taskDagGraphBO = JSONObject.parseObject(s, new TypeReference<TaskDagGraphBO>(){});
        taskDagGraphBO.setEdges(taskDagEdges);
        List<Long> priority1 = TaskDAGUtil.findPriority1(taskDagGraphBO);
        System.out.println(priority1);
    }

}

  • 9
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值