By Golang

  1. // Package graph creates a ItemGraph data structure for the Item type
  2. package graph
  3. import (
  4. "fmt"
  5. "sync"
  6. )
  7. // Item the type of the binary search tree
  8. type Item interface{}
  9. // Node a single node that composes the tree
  10. type Node struct {
  11. value Item
  12. }
  13. func (n *Node) String() string {
  14. return fmt.Sprintf("%v", n.value)
  15. }
  16. // ItemGraph the Items graph
  17. type ItemGraph struct {
  18. nodes []*Node
  19. edges map[Node][]*Node
  20. lock sync.RWMutex
  21. }
  22. // AddNode adds a node to the graph
  23. func (g *ItemGraph) AddNode(n *Node) {
  24. g.lock.Lock()
  25. g.nodes = append(g.nodes, n)
  26. g.lock.Unlock()
  27. }
  28. // AddEdge adds an edge to the graph
  29. func (g *ItemGraph) AddEdge(n1, n2 *Node) {
  30. g.lock.Lock()
  31. if g.edges == nil {
  32. g.edges = make(map[Node][]*Node)
  33. }
  34. g.edges[*n1] = append(g.edges[*n1], n2)
  35. g.edges[*n2] = append(g.edges[*n2], n1)
  36. g.lock.Unlock()
  37. }
  38. // AddEdge adds an edge to the graph
  39. func (g *ItemGraph) String() {
  40. g.lock.RLock()
  41. s := ""
  42. for i := 0; i < len(g.nodes); i++ {
  43. s += g.nodes[i].String() + " -> "
  44. near := g.edges[*g.nodes[i]]
  45. for j := 0; j < len(near); j++ {
  46. s += near[j].String() + " "
  47. }
  48. s += "\n"
  49. }
  50. fmt.Println(s)
  51. g.lock.RUnlock()
  52. }
  53. // Traverse implements the BFS traversing algorithm
  54. func (g *ItemGraph) Traverse(f func(*Node)) {
  55. g.lock.RLock()
  56. q := NodeQueue{}
  57. q.New()
  58. n := g.nodes[0]
  59. q.Enqueue(*n)
  60. visited := make(map[*Node]bool)
  61. for {
  62. if q.IsEmpty() {
  63. break
  64. }
  65. node := q.Dequeue()
  66. visited[node] = true
  67. near := g.edges[*node]
  68. for i := 0; i < len(near); i++ {
  69. j := near[i]
  70. if !visited[j] {
  71. q.Enqueue(*j)
  72. visited[j] = true
  73. }
  74. }
  75. if f != nil {
  76. f(node)
  77. }
  78. }
  79. g.lock.RUnlock()
  80. }