GoLang Program to Implement Breadth-First Search

GoLang Program to Implement Breadth-First Search

Graphs are everywhere in programming, from social networks and maps to recommendation systems and routing problems. One of the most important ways to explore a graph is Breadth-First Search (BFS). Unlike Depth-First Search (DFS), which explores as far as possible along a branch before backtracking, BFS explores all neighbors at the current depth before moving on to the next level. This makes BFS particularly useful for finding the shortest path in unweighted graphs or exploring levels in hierarchical data.

Pluralsight Logo
Accelerate your tech career
with hands-on learning.
Whether you're a tech newbie or a total pro,
get the skills and confidence to land your next move.
Start 10-Day Free Trial

Understanding BFS is crucial for any programmer dealing with graphs. It teaches concepts like queues, level-order traversal, and systematic exploration of data. In practical scenarios, BFS is used in shortest path algorithms, peer-to-peer networks, AI pathfinding, and even in solving puzzles and mazes. Implementing BFS in GoLang helps beginners grasp both graph theory and essential programming concepts like loops, queues, and adjacency lists.

Program 1: BFS Using a Queue

This first program demonstrates BFS using a queue. It traverses a graph represented as an adjacency list and prints the nodes in the order they are visited.

package main

import "fmt"

func bfs(graph map[int][]int, start int) {

    visited := make(map[int]bool)
    queue := []int{start}

    fmt.Print("BFS Traversal: ")

    for len(queue) > 0 {

        node := queue[0]
        queue = queue[1:]

        if !visited[node] {

            fmt.Printf("%d ", node)
            visited[node] = true

        }

        for _, neighbor := range graph[node] {

            if !visited[neighbor] {
                queue = append(queue, neighbor)
            }

        }

    }

}

func main() {

    graph := map[int][]int{
        1: {2, 3},
        2: {4, 5},
        3: {6},
        4: {},
        5: {},
        6: {},
    }

    bfs(graph, 1)

}

In this program, BFS uses a queue to explore nodes level by level. The visited map prevents revisiting nodes. Beginners can clearly see how BFS systematically explores all neighbors at the current level before moving deeper into the graph.

Program 2: BFS to Find the Shortest Path

BFS can be used to find the shortest path from a starting node to a target node in an unweighted graph. This version keeps track of distances while traversing.

package main

import "fmt"

func bfsShortestPath(graph map[int][]int, start, target int) int {

    visited := make(map[int]bool)
    queue := []int{start}
    distance := make(map[int]int)
    distance[start] = 0

    for len(queue) > 0 {

        node := queue[0]
        queue = queue[1:]

        if node == target {
            return distance[node]
        }

        for _, neighbor := range graph[node] {

            if !visited[neighbor] {

                visited[neighbor] = true
                distance[neighbor] = distance[node] + 1
                queue = append(queue, neighbor)

            }

        }

    }

    return -1

}

func main() {

    graph := map[int][]int{
        1: {2, 3},
        2: {4, 5},
        3: {6},
        4: {},
        5: {},
        6: {},
    }

    start, target := 1, 5

    dist := bfsShortestPath(graph, start, target)

    if dist != -1 {
        fmt.Printf("Shortest path from %d to %d is %d\n", start, target, dist)
    } else {
        fmt.Printf("No path found from %d to %d\n", start, target)
    }

}

This program demonstrates a practical application of BFS. The distance map keeps track of how far each node is from the starting point. Beginners can see how BFS naturally finds the shortest path in unweighted graphs.

Program 3: BFS for Level Order Traversal

In some applications, we may want to process a graph level by level, similar to BFS in trees. This version prints nodes grouped by their distance from the start node.

package main

import "fmt"

func bfsLevelOrder(graph map[int][]int, start int) {

    visited := make(map[int]bool)
    queue := []int{start}
    level := make(map[int]int)
    level[start] = 0

    fmt.Println("Level Order Traversal:")

    for len(queue) > 0 {

        node := queue[0]
        queue = queue[1:]

        if !visited[node] {

            fmt.Printf("Node %d at level %d\n", node, level[node])
            visited[node] = true

        }

        for _, neighbor := range graph[node] {

            if !visited[neighbor] {

                queue = append(queue, neighbor)
                level[neighbor] = level[node] + 1

            }

        }

    }

}

func main() {

    graph := map[int][]int{
        1: {2, 3},
        2: {4, 5},
        3: {6},
        4: {},
        5: {},
        6: {},
    }

    bfsLevelOrder(graph, 1)

}

This level-order approach is useful in scenarios like social network analysis, where we may want to know friends at distance 1, 2, or 3 from a user. Beginners can understand BFS’s ability to explore nodes layer by layer.

Program 4: BFS to Count Connected Components

BFS can also identify connected components in an undirected graph. This program counts all separate clusters in the graph.

package main

import "fmt"

func bfsComponent(graph map[int][]int, visited map[int]bool, start int) {

    queue := []int{start}

    for len(queue) > 0 {

        node := queue[0]
        queue = queue[1:]

        if !visited[node] {
            visited[node] = true
        }

        for _, neighbor := range graph[node] {

            if !visited[neighbor] {
                queue = append(queue, neighbor)
            }

        }

    }

}

func main() {

    graph := map[int][]int{
        1: {2},
        2: {1, 3},
        3: {2},
        4: {5},
        5: {4},
        6: {},
    }

    visited := make(map[int]bool)
    count := 0

    for node := range graph {

        if !visited[node] {

            bfsComponent(graph, visited, node)
            count++

        }

    }

    fmt.Printf("Number of connected components: %d\n", count)

}

By applying BFS from unvisited nodes, we explore entire connected components one by one. This helps beginners see how BFS can analyze the structure of a graph beyond simple traversal.

Frequently Asked Questions (FAQ)

Q1: What is Breadth-First Search (BFS)?
BFS is a graph traversal algorithm that explores all nodes at the current depth before moving to the next level, ensuring systematic exploration of the graph.

Q2: When should I use BFS?
BFS is ideal for finding the shortest path in unweighted graphs, exploring levels in hierarchical data, and analyzing connectivity in networks.

Q3: BFS vs DFS – which should I choose?
DFS goes deep along one branch first, while BFS explores nodes level by level. BFS is best for shortest paths or level-order tasks, whereas DFS is better for deep searches or recursion-based problems.

Q4: Can BFS handle cycles in graphs?
Yes, BFS uses a visited map or set to track nodes already explored, preventing infinite loops in cyclic graphs.

Q5: Is BFS easier than DFS?
BFS is conceptually simple for beginners because it uses a queue to explore nodes systematically, while DFS often relies on recursion or a stack for backtracking.

Conclusion

Breadth-First Search is an essential algorithm for exploring and analyzing graphs. Whether you are finding the shortest path, performing level-order traversal, or identifying connected components, BFS provides a structured and efficient approach.

By practicing BFS on various types of graphs—directed, undirected, weighted, or unweighted—beginners gain a solid understanding of graph theory and algorithmic thinking. Experimenting with BFS also prepares you for more advanced algorithms like Dijkstra’s shortest path or network flow problems.

Scroll to Top