123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104 |
- package toposort
- // Copied from https://github.com/philopon/go-toposort
- type Graph struct {
- nodes []string
- outputs map[string]map[string]int
- inputs map[string]int
- }
- func NewGraph() *Graph {
- return &Graph{
- nodes: []string{},
- inputs: map[string]int{},
- outputs: map[string]map[string]int{},
- }
- }
- func (g *Graph) AddNode(name string) bool {
- g.nodes = append(g.nodes, name)
- if _, ok := g.outputs[name]; ok {
- return false
- }
- g.outputs[name] = make(map[string]int)
- g.inputs[name] = 0
- return true
- }
- func (g *Graph) AddNodes(names ...string) bool {
- for _, name := range names {
- if ok := g.AddNode(name); !ok {
- return false
- }
- }
- return true
- }
- func (g *Graph) AddEdge(from, to string) bool {
- m, ok := g.outputs[from]
- if !ok {
- return false
- }
- m[to] = len(m) + 1
- g.inputs[to]++
- return true
- }
- func (g *Graph) unsafeRemoveEdge(from, to string) {
- delete(g.outputs[from], to)
- g.inputs[to]--
- }
- func (g *Graph) RemoveEdge(from, to string) bool {
- if _, ok := g.outputs[from]; !ok {
- return false
- }
- g.unsafeRemoveEdge(from, to)
- return true
- }
- func (g *Graph) Toposort() ([]string, bool) {
- L := make([]string, 0, len(g.nodes))
- S := make([]string, 0, len(g.nodes))
- for _, n := range g.nodes {
- if g.inputs[n] == 0 {
- S = append(S, n)
- }
- }
- for len(S) > 0 {
- var n string
- n, S = S[0], S[1:]
- L = append(L, n)
- ms := make([]string, len(g.outputs[n]))
- for m, i := range g.outputs[n] {
- ms[i-1] = m
- }
- for _, m := range ms {
- g.unsafeRemoveEdge(n, m)
- if g.inputs[m] == 0 {
- S = append(S, m)
- }
- }
- }
- N := 0
- for _, v := range g.inputs {
- N += v
- }
- if N > 0 {
- return L, false
- }
- return L, true
- }
|