├── .gitignore ├── README.md └── main.go /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # go-graph-traversing 2 | Graph DFS and BFS implementation in golang 3 | 4 | ### Breadth First Search 5 | ![breadth_first_traversal](https://user-images.githubusercontent.com/3184210/70855231-ee168580-1ec7-11ea-82fe-78927fd8bcdb.jpg) 6 | ``` 7 | Algorithm BFS(G, v) 8 | Q ← new empty FIFO queue 9 | Mark v as visited. 10 | Q.enqueue(v) 11 | while Q is not empty 12 | a ← Q.dequeue() 13 | // Perform some operation on a. 14 | for all unvisited neighbors x of a 15 | Mark x as visited. 16 | Q.enqueue(x) 17 | ``` 18 | [BFS visualization](https://www.cs.usfca.edu/~galles/visualization/BFS.html) 19 | 20 | 21 | ### Depth First Search 22 | ![dfs](https://user-images.githubusercontent.com/3184210/70855249-3d5cb600-1ec8-11ea-98c3-e692f30dd5f0.gif) 23 | ``` 24 | Algorithm DFS(G, v) 25 | if v is already visited 26 | return 27 | Mark v as visited. 28 | // Perform some operation on v. 29 | for all neighbors x of v 30 | DFS(G, x) 31 | ``` 32 | [DFS visualization](https://www.cs.usfca.edu/~galles/visualization/DFS.html) 33 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | func main() { 9 | fmt.Println("GoLang, Graph DFS and BFS implementation") 10 | fmt.Println("DFS : Depth First Search") 11 | fmt.Println("BFS : Breadth First Search") 12 | 13 | g := NewGraph() 14 | 15 | g.AddVertex("ajinkya") 16 | g.AddVertex("francesc") 17 | g.AddVertex("manish") 18 | g.AddVertex("albert") 19 | 20 | g.AddEdge("albert", "ajinkya") 21 | g.AddEdge("ajinkya", "albert") 22 | g.AddEdge("francesc", "ajinkya") 23 | g.AddEdge("francesc", "manish") 24 | g.AddEdge("manish", "francesc") 25 | g.AddEdge("manish", "albert") 26 | 27 | g.DFS("francesc") 28 | g.CreatePath("francesc", "albert") 29 | } 30 | 31 | func NewGraph() Graph { 32 | return Graph{ 33 | adjacency: make(map[string][]string), 34 | } 35 | } 36 | 37 | type Graph struct { 38 | adjacency map[string][]string 39 | } 40 | 41 | func (g *Graph) AddVertex(vertex string) bool { 42 | if _, ok := g.adjacency[vertex]; ok { 43 | fmt.Printf("vertex %v already exists\n", vertex) 44 | return false 45 | } 46 | g.adjacency[vertex] = []string{} 47 | return true 48 | } 49 | 50 | func (g *Graph) AddEdge(vertex, node string) bool { 51 | if _, ok := g.adjacency[vertex]; !ok { 52 | fmt.Printf("vertex %v does not exists\n", vertex) 53 | return false 54 | } 55 | if ok := contains(g.adjacency[vertex], node); ok { 56 | fmt.Printf("node %v already exists\n", node) 57 | return false 58 | } 59 | 60 | g.adjacency[vertex] = append(g.adjacency[vertex], node) 61 | return true 62 | } 63 | 64 | func (g Graph) BFS(startingNode string) { 65 | visited := g.createVisited() 66 | var q []string 67 | 68 | visited[startingNode] = true 69 | q = append(q, startingNode) 70 | 71 | for len(q) > 0 { 72 | var current string 73 | current, q = q[0], q[1:] 74 | fmt.Println("BFS", current) 75 | for _, node := range g.adjacency[current] { 76 | if !visited[node] { 77 | q = append(q, node) 78 | visited[node] = true 79 | } 80 | } 81 | } 82 | } 83 | 84 | func (g Graph) DFS(startingNode string) { 85 | visited := g.createVisited() 86 | g.dfsRecursive(startingNode, visited) 87 | } 88 | 89 | func (g Graph) dfsRecursive(startingNode string, visited map[string]bool) { 90 | visited[startingNode] = true 91 | fmt.Println("DFS", startingNode) 92 | for _, node := range g.adjacency[startingNode] { 93 | if !visited[node] { 94 | g.dfsRecursive(node, visited) 95 | } 96 | } 97 | } 98 | 99 | func (g Graph) CreatePath(firstNode, secondNode string) bool { 100 | visited := g.createVisited() 101 | var ( 102 | path []string 103 | q []string 104 | ) 105 | q = append(q, firstNode) 106 | visited[firstNode] = true 107 | 108 | for len(q) > 0 { 109 | var currentNode string 110 | currentNode, q = q[0], q[1:] 111 | path = append(path, currentNode) 112 | edges := g.adjacency[currentNode] 113 | if contains(edges, secondNode) { 114 | path = append(path, secondNode) 115 | fmt.Println(strings.Join(path, "->")) 116 | return true 117 | } 118 | 119 | for _, node := range g.adjacency[currentNode] { 120 | if !visited[node] { 121 | visited[node] = true 122 | q = append(q, node) 123 | } 124 | } 125 | } 126 | fmt.Println("no link found") 127 | return false 128 | } 129 | 130 | func (g Graph) createVisited() map[string]bool { 131 | visited := make(map[string]bool, len(g.adjacency)) 132 | for key := range g.adjacency { 133 | visited[key] = false 134 | } 135 | return visited 136 | } 137 | 138 | func contains(slice []string, item string) bool { 139 | set := make(map[string]struct{}, len(slice)) 140 | for _, s := range slice { 141 | set[s] = struct{}{} 142 | } 143 | 144 | _, ok := set[item] 145 | return ok 146 | } 147 | --------------------------------------------------------------------------------