DAG以及任务调度

本文介绍了有向无环图(DAG)的概念及其在任务调度中的应用。阐述了图的遍历方法,特别是拓扑排序,以及如何在DAG中寻找入度为0的顶点进行遍历。此外,还探讨了任务调度组件如何利用DAG来管理任务的执行顺序,确保任务按照依赖关系正确执行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

有向无环图

  图的遍历是指从图中的某一个顶点出发,按照某种搜索方法沿着图中的边对图中的所有顶点访问一次且仅访问一次。图的遍历主要有两种算法:BFS和DFS。
  对于任何有向无环图(DAG)而言,其拓扑排序为其所有结点的一个线性排序(同一个有向图可能存在多个这样的结点排序)。该排序满足这样的条件——对于图中的任意两个结点U和V,若存在一条有向边从U指向V,则在拓扑排序中U一定出现在V前面。通俗来讲:拓扑排序是一个有向无环图(DAG)的所有顶点的线性序列,该序列必须满足两个条件:

  1. 每个顶点出现且只出现一次
  2. 若存在一条从顶点A到顶点B的路径,那么在序列中顶点 A出现在顶点 B的前面

寻找出DAG的拓扑排序

  1. 从DAG图中选择一个入度为0的顶点并输出
  2. 从图中删除该顶点和所有以它为起点的有向边
  3. 重复1和2直到当前的DAG图为空或当前图中不存在入度为0的顶点为止。后一种情况说明有向图中必然存在环

  假设有向图中不存在起点和终点为同一结点的有向边。有向图结点的入度(indegree)和出度(outdegree)的概念:
  入度:设有向图中有一结点V,其入度即为当前所有从其他结点出发,终点为V的的边的数目。也就是所有指向V的有向边的数目。
  出度:设有向图中有一结点V,其出度即为当前所有起点为V,指向其他结点的边的数目。也就是所有由V发出的边的数目。

  与普通的广度优先遍历可以从该DAG任意一个结点开始遍历不同,这里应当保存每一个结点对应的入度,并在遍历的每一层选取入度为0的结点开始遍历。下面给出广度优先遍历拓扑排序的代码:

算法描述:
初始化一个Map或者类似数据结构来保存每一个结点的入度。
对于图中的每一个结点的子结点,将其子结点的入度加1。
选取入度为0的任意一个结点开始遍历,并将该节点加入输出。
对于遍历过的每个结点,更新其子结点的入度:将子结点的入度减1。
重复步骤3,直到遍历完所有的结点。
如果无法遍历完所有的结点,则意味着当前的图不是有向无环图。不存在拓扑排序。

public class TopologicalSort {
   
  /**
   * 判断是否有环及拓扑排序结果
   *
   * 有向无环图(DAG)才有拓扑(topological)排序
   * 广度优先遍历的主要做法:
   *    1、遍历图中所有的顶点,将入度为0的顶点入队列。
   *    2、从队列中poll出一个顶点,更新该顶点的邻接点的入度(减1),如果邻接点的入度减1之后等于0,则将该邻接点入队列。
   *    3、一直执行第2步,直到队列为空。
   * 如果无法遍历完所有的结点,则意味着当前的图不是有向无环图。不存在拓扑排序。
   *
   *
   * @return key返回的是状态, 如果成功(无环)为true, 失败则有环, value为拓扑排序结果(可能是其中一种)
   */
  private Map.Entry<Boolean, List<Vertex>> topologicalSort() {
   
	//入度为0的结点队列
    Queue<Vertex> zeroIndegreeVertexQueue = new LinkedList<>();
    //保存结果
    List<Vertex> topoResultList = new ArrayList<>();
    //保存入度不为0的结点
    Map<Vertex, Integer> notZeroIndegreeVertexMap = new HashMap<>();
    //扫描所有的顶点,将入度为0的顶点入队列
    for (Map.Entry<Vertex, VertexInfo> vertices : verticesMap.entrySet()) {
   
      Vertex vertex = vertices.getKey();
      int inDegree = getIndegree(vertex);

      if (inDegree == 0) {
   
        zeroIndegreeVertexQueue.add(vertex);
        topoResultList.add(vertex);
      } else {
   
        notZeroIndegreeVertexMap.put(vertex, inDegree);
      }
    }
	//扫描完后,没有入度为0的结点,说明有环,直接返回
    if(zeroIndegreeVertexQueue.isEmpty()){
   
      return new AbstractMap.SimpleEntry(false, topoResultList);
    }
    //采用topology算法, 删除入度为0的结点和它的关联边
    while (!zeroIndegreeVertexQueue.isEmpty()) {
   
      Vertex v = zeroIndegreeVertexQueue.poll();
      //得到相邻结点
      Set<Vertex> subsequentNodes = getSubsequentNodes(v);
      for 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值