toposort.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. package toposort
  2. import (
  3. "bytes"
  4. "fmt"
  5. "sort"
  6. )
  7. // Reworked from https://github.com/philopon/go-toposort
  8. type Graph struct {
  9. // Outgoing connections for every node.
  10. outputs map[string]map[string]int
  11. // How many parents each node has.
  12. inputs map[string]int
  13. }
  14. // NewGraph initializes a new Graph.
  15. func NewGraph() *Graph {
  16. return &Graph{
  17. inputs: map[string]int{},
  18. outputs: map[string]map[string]int{},
  19. }
  20. }
  21. // Copy clones the graph and returns the independent copy.
  22. func (g *Graph) Copy() *Graph {
  23. clone := NewGraph()
  24. for k, v := range g.inputs {
  25. clone.inputs[k] = v
  26. }
  27. for k1, v1 := range g.outputs {
  28. m := map[string]int{}
  29. clone.outputs[k1] = m
  30. for k2, v2 := range v1 {
  31. m[k2] = v2
  32. }
  33. }
  34. return clone
  35. }
  36. // AddNode inserts a new node into the graph.
  37. func (g *Graph) AddNode(name string) bool {
  38. if _, exists := g.outputs[name]; exists {
  39. return false
  40. }
  41. g.outputs[name] = make(map[string]int)
  42. g.inputs[name] = 0
  43. return true
  44. }
  45. // AddNodes inserts multiple nodes into the graph at once.
  46. func (g *Graph) AddNodes(names ...string) bool {
  47. for _, name := range names {
  48. if ok := g.AddNode(name); !ok {
  49. return false
  50. }
  51. }
  52. return true
  53. }
  54. // AddEdge inserts the link from "from" node to "to" node.
  55. func (g *Graph) AddEdge(from, to string) int {
  56. m, ok := g.outputs[from]
  57. if !ok {
  58. return 0
  59. }
  60. m[to] = len(m) + 1
  61. ni := g.inputs[to] + 1
  62. g.inputs[to] = ni
  63. return ni
  64. }
  65. // ReindexNode updates the internal representation of the node after edge removals.
  66. func (g *Graph) ReindexNode(node string) {
  67. children, ok := g.outputs[node]
  68. if !ok {
  69. return
  70. }
  71. keys := []string{}
  72. for key := range children {
  73. keys = append(keys, key)
  74. }
  75. sort.Strings(keys)
  76. for i, key := range keys {
  77. children[key] = i + 1
  78. }
  79. }
  80. func (g *Graph) unsafeRemoveEdge(from, to string) {
  81. delete(g.outputs[from], to)
  82. g.inputs[to]--
  83. }
  84. // RemoveEdge deletes the link from "from" node to "to" node.
  85. // Call ReindexNode(from) after you finish modifying the edges.
  86. func (g *Graph) RemoveEdge(from, to string) bool {
  87. if _, ok := g.outputs[from]; !ok {
  88. return false
  89. }
  90. g.unsafeRemoveEdge(from, to)
  91. return true
  92. }
  93. // Toposort sorts the nodes in the graph in topological order.
  94. func (g *Graph) Toposort() ([]string, bool) {
  95. L := make([]string, 0, len(g.outputs))
  96. S := make([]string, 0, len(g.outputs))
  97. for n := range g.outputs {
  98. if g.inputs[n] == 0 {
  99. S = append(S, n)
  100. }
  101. }
  102. sort.Strings(S)
  103. for len(S) > 0 {
  104. var n string
  105. n, S = S[0], S[1:]
  106. L = append(L, n)
  107. ms := make([]string, len(g.outputs[n]))
  108. for m, i := range g.outputs[n] {
  109. ms[i-1] = m
  110. }
  111. for _, m := range ms {
  112. g.unsafeRemoveEdge(n, m)
  113. if g.inputs[m] == 0 {
  114. S = append(S, m)
  115. }
  116. }
  117. }
  118. N := 0
  119. for _, v := range g.inputs {
  120. N += v
  121. }
  122. if N > 0 {
  123. return L, false
  124. }
  125. return L, true
  126. }
  127. // BreadthSort sorts the nodes in the graph in BFS order.
  128. func (g *Graph) BreadthSort() []string {
  129. L := make([]string, 0, len(g.outputs))
  130. S := make([]string, 0, len(g.outputs))
  131. for n := range g.outputs {
  132. if g.inputs[n] == 0 {
  133. S = append(S, n)
  134. }
  135. }
  136. visited := map[string]bool{}
  137. for len(S) > 0 {
  138. node := S[0]
  139. S = S[1:]
  140. if _, exists := visited[node]; !exists {
  141. L = append(L, node)
  142. visited[node] = true
  143. for child := range g.outputs[node] {
  144. S = append(S, child)
  145. }
  146. }
  147. }
  148. return L
  149. }
  150. // FindCycle returns the cycle in the graph which contains "seed" node.
  151. func (g *Graph) FindCycle(seed string) []string {
  152. type edge struct {
  153. node string
  154. parent string
  155. }
  156. S := make([]edge, 0, len(g.outputs))
  157. S = append(S, edge{seed, ""})
  158. visited := map[string]string{}
  159. for len(S) > 0 {
  160. e := S[0]
  161. S = S[1:]
  162. if parent, exists := visited[e.node]; !exists || parent == "" {
  163. visited[e.node] = e.parent
  164. for child := range g.outputs[e.node] {
  165. S = append(S, edge{child, e.node})
  166. }
  167. }
  168. if e.node == seed && e.parent != "" {
  169. result := []string{}
  170. node := e.parent
  171. for node != seed {
  172. result = append(result, node)
  173. node = visited[node]
  174. }
  175. result = append(result, seed)
  176. // reverse
  177. for left, right := 0, len(result)-1; left < right; left, right = left+1, right-1 {
  178. result[left], result[right] = result[right], result[left]
  179. }
  180. return result
  181. }
  182. }
  183. return []string{}
  184. }
  185. // FindParents returns the other ends of incoming edges.
  186. func (g *Graph) FindParents(to string) []string {
  187. result := []string{}
  188. for node, children := range g.outputs {
  189. if _, exists := children[to]; exists {
  190. result = append(result, node)
  191. }
  192. }
  193. return result
  194. }
  195. // FindChildren returns the other ends of outgoing edges.
  196. func (g *Graph) FindChildren(from string) []string {
  197. result := []string{}
  198. for child := range g.outputs[from] {
  199. result = append(result, child)
  200. }
  201. return result
  202. }
  203. // Serialize outputs the graph in Graphviz format.
  204. func (g *Graph) Serialize(sorted []string) string {
  205. node2index := map[string]int{}
  206. for index, node := range sorted {
  207. node2index[node] = index
  208. }
  209. var buffer bytes.Buffer
  210. buffer.WriteString("digraph Hercules {\n")
  211. nodesFrom := []string{}
  212. for nodeFrom := range g.outputs {
  213. nodesFrom = append(nodesFrom, nodeFrom)
  214. }
  215. sort.Strings(nodesFrom)
  216. for _, nodeFrom := range nodesFrom {
  217. links := []string{}
  218. for nodeTo := range g.outputs[nodeFrom] {
  219. links = append(links, nodeTo)
  220. }
  221. sort.Strings(links)
  222. for _, nodeTo := range links {
  223. buffer.WriteString(fmt.Sprintf(" \"%d %s\" -> \"%d %s\"\n",
  224. node2index[nodeFrom], nodeFrom, node2index[nodeTo], nodeTo))
  225. }
  226. }
  227. buffer.WriteString("}")
  228. return buffer.String()
  229. }