类似于make的程序的数据结构

时间:2014-05-23 09:25:55

标签: data-structures graph makefile directed-acyclic-graphs

给定有向非循环图 G ,有没有办法表示 G ,以便在 O(log | G |)中可以执行以下操作时间?

  1. G 中删除节点 N 。可以假设没有边缘导致 N ,但是一些边缘可能会导致 N 。可以假设 N 被标记。
  2. 标记节点(所有节点均以未标记开始)
  3. G 中返回一个没有边缘的未标记节点。
  4. 这些操作对应于 make 之类的程序的基本操作,该程序在执行规则之前计算完整的依赖图:

    • (1)对应于将目标标记为 done
    • (2)对应于将目标标记为已启动
    • (3)对应于找到一个可以立即启动的目标,因为它的所有先决条件都已完成。

2 个答案:

答案 0 :(得分:1)

我不记得运行时间的复杂性,但也许你可以使用有向图(我最初说 tree 但是某些节点可能有多个父母 - 我不确定如何最好地代表那个??

根据您的要求3,对于没有边缘通向它们的所有节点的集合S,创建"虚拟"的错误是什么?根节点,边缘通向没有父节点的每个节点?这会将要求3更改为"返回G中未标记的节点,该节点具有来自根节点的边缘,导致它#34;。

答案 1 :(得分:0)

这是“计算机编程艺术”第一卷中讨论的拓扑排序算法的一种变体。 1(基本算法),第1节。 2.2.3在Go中实现,实现了所需的功能:

package graph

import "os/exec"

// a user of this package shall initialize each node with the command to be
// run and a set of other nodes that can only be executed when this node has
// been finished. It is assumed that no cycles exist.
type Node struct {
    exec.Cmd
    incoming int // populated by Execute()
    Outgoing []Node
}

type Graph struct {
    Nodes []Node
}

// execute a graph
func (g *Graph) Execute() {
    var dispatcher = make(chan *Node)

    for _, n := range g.Nodes {
        for _, nn := range n.Outgoing {
            nn.incoming++
        }
    }

    for _, n := range g.Nodes {
        if n.incoming == 0 {
            go n.run(dispatcher)
        }
    }

    // each node will spawn one task
    for _ = range g.Nodes {
        n := <-dispatcher
        for _, nn := range n.Outgoing {
            nn.incoming--
            if nn.incoming == 0 {
                go n.run(dispatcher)
            }
        }
    }
}

// run the function corresponding to a node and notify when done
func (n *Node) run(dispatcher chan<- *Node) {
    n.Cmd.Run()
    dispatcher <- n
}

该算法不是一组撤消任务,而是直接生成工人并使用渠道收集它们。