GoLang Program to Implement Depth-First Search

GoLang Program to Implement Depth-First Search

Graphs are everywhere in programming, from social networks to web pages, maps, and recommendation systems. One of the fundamental ways to explore graphs is Depth-First Search (DFS). DFS is a graph traversal algorithm that explores as far as possible along each branch before backtracking. It’s simple, elegant, and forms the foundation for solving many complex problems like finding connected components, detecting cycles, or pathfinding.

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

Depth-First Search matters because it allows programmers to explore structured data systematically. Unlike simple loops over arrays, DFS handles graphs of varying shapes and sizes efficiently. For beginners, implementing DFS in GoLang is a great way to understand recursion, stacks, and graph data structures. It’s widely used in real-world scenarios, including maze solving, AI for games, network connectivity checks, and many other applications.

Program 1: Recursive Depth-First Search on an Adjacency List

This program demonstrates DFS using recursion, one of the most natural ways to implement the algorithm. It traverses a graph represented as an adjacency list and prints the order in which nodes are visited.

package main

import "fmt"

func dfsRecursive(graph map[int][]int, visited map[int]bool, node int) {

    visited[node] = true

    fmt.Printf("%d ", node)

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

        if !visited[neighbor] {
            dfsRecursive(graph, visited, neighbor)
        }

    }

}

func main() {

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

    visited := make(map[int]bool)

    fmt.Print("DFS Traversal (Recursive): ")
    dfsRecursive(graph, visited, 1)

}

In this program, recursion helps automatically manage the traversal stack. Each node is marked as visited to avoid revisiting it. Beginners can clearly see how DFS explores one branch completely before backtracking to the next branch.

Program 2: Iterative Depth-First Search Using a Stack

Sometimes recursion can be limited by the maximum stack size. This version uses an explicit stack to implement DFS iteratively. It’s also easier to adapt for large graphs.

package main

import "fmt"

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

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

    fmt.Print("DFS Traversal (Iterative): ")
    for len(stack) > 0 {

        node := stack[len(stack)-1]
        stack = stack[:len(stack)-1]

        if !visited[node] {

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

        }

        for i := len(graph[node]) - 1; i >= 0; i-- {

            neighbor := graph[node][i]

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

        }

    }

}

func main() {

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

    dfsIterative(graph, 1)

}

Here, the stack explicitly stores the nodes to visit. Iterative DFS mimics the call stack of recursion, giving beginners a concrete idea of how backtracking works in DFS.

Program 3: DFS for Detecting a Path Between Two Nodes

This program uses DFS to check if there’s a path from a starting node to a target node. It’s a practical example of DFS for solving real problems.

package main

import "fmt"

func dfsPathExists(graph map[int][]int, visited map[int]bool, current, target int) bool {

    if current == target {
        return true
    }

    visited[current] = true

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

        if !visited[neighbor] {

            if dfsPathExists(graph, visited, neighbor, target) {
                return true
            }

        }

    }

    return false

}

func main() {

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

    visited := make(map[int]bool)
    start, target := 1, 5

    if dfsPathExists(graph, visited, start, target) {
        fmt.Printf("Path exists from %d to %d\n", start, target)
    } else {
        fmt.Printf("No path exists from %d to %d\n", start, target)
    }

}

This shows how DFS can be adapted to solve practical problems like pathfinding. The recursive traversal stops as soon as the target is found, making it efficient for searches in large graphs.

Program 4: DFS to Count Connected Components

DFS is very useful for analyzing graph connectivity. This program counts the number of connected components in an undirected graph.

package main

import "fmt"

func dfsComponent(graph map[int][]int, visited map[int]bool, node int) {

    visited[node] = true

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

        if !visited[neighbor] {
            dfsComponent(graph, visited, 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] {

            dfsComponent(graph, visited, node)
            count++

        }

    }

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

}

By applying DFS repeatedly from unvisited nodes, the algorithm identifies all connected components. Beginners can see how DFS systematically explores the entire graph and separates different clusters.

Frequently Asked Questions (FAQ)

Q1: What is Depth-First Search (DFS)?
DFS is a graph traversal algorithm that explores a branch completely before backtracking, ensuring all nodes are visited systematically.

Q2: When should I use DFS?
DFS is useful for pathfinding, cycle detection, topological sorting, maze solving, and analyzing graph connectivity.

Q3: DFS vs BFS – which should I use?
DFS explores as deep as possible first, while BFS explores all neighbors level by level. DFS is better for deep searches or solving recursion-based problems, while BFS is better for shortest path problems in unweighted graphs.

Q4: Can DFS handle cycles in graphs?
Yes, by maintaining a visited map, DFS avoids revisiting nodes, preventing infinite loops.

Q5: Is DFS easier with recursion or iteration?
Recursion is often simpler and elegant for beginners, while iterative DFS is safer for very large graphs to avoid stack overflow.

Conclusion

Depth-First Search is a fundamental algorithm for any programmer dealing with graphs. By learning both recursive and iterative approaches, as well as applications like pathfinding and counting connected components, beginners gain a strong foundation in graph theory and algorithmic thinking.

Practicing DFS on different types of graphs—directed, undirected, weighted, or unweighted—will help you confidently apply this algorithm in real-world scenarios and prepare you for more advanced graph algorithms like topological sort, cycle detection, and strongly connected components.

Scroll to Top