Graph Traversal Algorithms Explained: DFS, BFS & Applications

Software Engineer
|
July 7, 2025
Graph Traversal Algorithms Explained: DFS, BFS & Applications

Graphs are a core data structure for representing interconnected data, enabling efficient exploration of complex networks. At the heart of this process are graph traversal algorithms. Two of the most common are Depth-First Search (DFS) and Breadth-First Search (BFS). They're often among the first algorithms people learn, not just because they’re easy to implement, but because they form the basis for many more advanced techniques. 

This blog will cover the fundamentals behind graph traversal, focusing on how DFS and BFS work and why they're so widely used. By understanding the basics, you’ll be better prepared to apply these algorithms effectively and recognize their role in more complex graph-based solutions.

What is Graph Traversal?

To understand what graph traversal means, let’s break it into two key components: what a graph is and what it means to traverse one.

A graph is a data structure made up of nodes (also called vertices) and edges that connect pairs of nodes. Graphs can be directed or undirected, weighted or unweighted, and they can represent a wide variety of relationships, from friendships in a social network to links between web pages or routes on a map. This flexibility makes graphs a powerful way to explore connections within your data.

Figure: friend of friend of a person with id “123”

Unlike linear data structures such as arrays or linked lists, graphs can model more complex systems. They are especially useful in scenarios where relationships matter just as much as individual entities. Because graphs do not store data sequentially, they require a different approach to navigation. This is done by visiting nodes one by one, following the edges that link them—a process known as graph traversal.

How does Graph Traversal Work?

As we’ve defined, graph traversal is the process of visiting nodes in a graph by following the edges that connect them. But simply moving from node to node without a clear strategy can quickly become inefficient, especially in large or densely connected networks. To address this, traversal algorithms provide a systematic way to explore graphs and extract useful information. When implemented correctly, they ensure each node is visited only once and prevent issues like infinite loops in cyclic graphs.

Graph traversal methods often follow a similar approach: Starting with a node, they evaluate whether it meets the goal, then moving on to adjacent nodes based on an evaluation function, f(n), that helps to prioritize which nodes to expand during the search. The function is often defined as:

$$
f(n)=g(n)+h(n)
$$

f(n) returns the estimated cost of a path through n, where g(n) is the cost from the start node to the current node n, and h(n) is the heuristic estimate of the cost from the current node n to the goal. 

The choice of rules can make a significant difference, depending on the graph’s structure and the task at hand. Selecting the right traversal method can greatly improve efficiency, especially when working with large graphs. When deciding which algorithm to use, it's important to consider factors like time and space constraints, the purpose of the traversal, and the nature of the graph, such as whether it's directed or undirected, weighted or unweighted.

Before we can decide which one fits best, we need to understand the options available.

Types of Graph Traversal Algorithms

While there are numerous graph traversal algorithms, we will focus on Depth-First Search (DFS) and Breadth-First Search (BFS), which are frequently incorporated into or extended by other algorithms. The basic implementations of DFS and BFS are blind search algorithms, also known as uninformed search algorithms. This means they do not use any heuristic or domain-specific information to guide the traversal. Instead, they explore the graph based solely on its structure and the order in which nodes are encountered.

Let’s dive deeper into the details, starting with DFS.

Depth-First Search (DFS) 

DFS explores a graph by going as far as possible along one path before backtracking. From the starting node, it visits an unvisited neighbor, following unvisited neighbors down that path until it reaches a node with no more unexplored connections. At that point, it backtracks to the previous node and repeats the process.

DFS evaluates the cost solely based on the node’s depth in the search tree, and uses the following evaluation function:

$$
g(n)=depth(n),h(n)=0
$$

By choosing the path with the highest estimated cost through n, we prioritize expanding the deepest unvisited nodes. This behavior allows us to use a stack to keep track of the path, where we expand the most recently added node. This is either done explicitly with a data structure, or implicitly through the call stack in a recursive implementation. This leads to two variations of DFS: Iterative DFS and recursive DFS.

Figure: DFS traversal starting from node A. Nodes are visited in the order A → B → D → E → C.

Iterative DFS Implementation (Python)

def dfs_iterative(graph, start):
   # Non-recursive DFS where stack maintains current path from root
   visited = set()
   stack = [start]             # Stack represents current path from root
  
   while stack:
       node = stack.pop()      # Pop current node
      
       if node not in visited:
           visited.add(node)
           print(node)         # Process node
          
           stack.append(node)  # Push back to maintain path
          
           # Find first unvisited neighbor
           for neighbor in reversed(graph.get(node, [])):
               if neighbor not in visited:
                   stack.append(neighbor)  # Push to extend path

       # If already visited, node is already popped (backtrack)

Recursive DFS Implementation (Python)

def dfs_recursive(graph, node, visited=set()):
   if node not in visited:
       visited.add(node)
       print(node)  # Process the node

       for neighbor in graph.get(node, []):
           dfs_recursive(graph, neighbor, visited)

Since recursive DFS uses the call stack, the code is compact and often easier to follow. On the other hand, iterative DFS uses an explicit stack, avoiding function call overhead and limitations of the call stack size. The choice between them often depends on the specifics of the problem, such as graph depth, need for performance tuning, or whether the language or environment imposes strict recursion limits.

Breadth-First Search (BFS) 

BFS explores a graph by visiting all nodes at the current depth before moving deeper. Starting from the initial node, it visits all unvisited neighbors, then processes each of those neighbors’ unvisited neighbors in turn, gradually expanding outward from the source.

BFS uses the same evaluation function as DFS:

$$
g(n)=depth(n),h(n)=0
$$

Unlike DFS, which follows a single path as far as it can before backtracking, BFS systematically explores all nearby nodes before moving further out. It chooses the path with the lowest estimated cost through n, prioritizing the expansion of the nearest unvisited nodes. To manage this, BFS uses a queue to track nodes to visit next, always processing the earliest added node first. BFS is typically implemented iteratively, since it relies on a queue for FIFO (First In, First Out) ordering, whereas recursion uses a stack, which follows LIFO (Last In, First Out) behavior.

Figure: BFS traversal starting from node A. Nodes are visited in the order A → B → C → D → E.

Iterative BFS Implementation (Python)

def bfs(graph, start):
    visited = set()
    queue = [start]

    while queue:
        node = queue.pop(0)                 # Dequeue from the front
        if node not in visited:
            visited.add(node)
            print(node)
            for neighbor in graph.get(node, []):
                if neighbor not in visited:
                    queue.append(neighbor)  # Enqueue to the back

To try out the the Python code from the blog, you can add on the following code snippet:

if __name__ == "__main__":
   graph = {
       'A': ['B', 'C'],
       'B': ['D', 'E'],
       'C': ['E'],
   }

   print("dfs_iterative:")
   dfs_iterative(graph, 'A')
   print("dfs_recursive:")
   dfs_recursive(graph, 'A')
   print("bfs:")
   bfs(graph, 'A')

Benefits of Graph Traversal Algorithms

Efficient Network Traversal

Graph traversal provides a systematic way to explore graphs efficiently, especially in large or densely connected networks where naive approaches can quickly become resource-intensive. Traversal algorithms like BFS and DFS avoid unnecessary repeated processing by marking nodes as visited, ensuring that each node is explored only once. This not only reduces overhead but also makes it possible to scale exploration across complex graph structures. 

Discovering Reachability

Traversal helps identify which nodes are reachable from a given starting point. By systematically visiting neighbors, we can detect disconnected components, validate network connectivity, or determine access within permission graphs. This is useful in a wide range of scenarios, such as validating whether a network is fully connected, checking if a user can access certain content in a permission graph, or identifying disconnected components in an undirected graph.

Foundations of Complex Algorithms

DFS and BFS power many advanced algorithms, including cycle detection, topological sorting, and shortest path finding. The right choice often depends on your graph and goal, but many higher-level methods build directly on these traversal strategies. For a deeper dive into those more specialized techniques, check out our post outlining more graph search algorithms.

Graph Traversal examples

Traversal isn’t just a theoretical concept. It plays a central role in many real-world systems. Let’s look at practical examples across industries to see how graph traversal helps solve everyday problems. 

Social Networks

  • Friend recommendations by exploring mutual connections through BFS.
  • Community detection using DFS to identify clusters in the social graph.
  • Influencer discovery by traversing interaction graphs to locate high-connectivity nodes.

Recommendation Systems

  • Similar item discovery through BFS over co-purchase or similarity graphs.
  • User-based recommendations by identifying others with shared behavior patterns.
  • Context-aware suggestions by traversing tags, categories, or content relationships.

Cybersecurity and IT Infrastructure

  • Compromised device impact tracing with BFS to map exposure.
  • Permission auditing via DFS to trace nested access rights.
  • Lateral movement detection by exploring reachable systems from a single node.

Supply Chain and Logistics

  • Delivery path optimization using BFS to find shortest supply routes.
  • Recall tracing via DFS to identify all downstream locations affected by an issue.
  • Bottleneck detection by analyzing overlapping routes or overloaded hubs.

Choosing the Right Graph Traversal Algorithm

While DFS and BFS are often interchangeable at a basic level, their strengths emerge in different contexts. Recognizing what each algorithm excels at can help you choose the one that best fits your use case.

When to Use DFS

DFS is arguably the most widely used graph search technique due to its simplicity, versatility, and suitability for problems that require deep exploration or backtracking. It’s a strong choice when the goal is to analyze structure, exhaustively search paths, or explore nested relationships. It’s particularly effective in the following scenarios:

  • Cycle detection: DFS makes it easy to track the current path and detect cycles, especially in directed graphs.
  • Topological sorting: Many implementations rely on DFS to order nodes with dependency constraints.
  • Backtracking problems: Puzzles like Sudoku, maze solving, and the N-Queens problem benefit from DFS’s recursive exploration.
  • Pathfinding in deep or sparsely connected graphs: DFS tends to use less memory because it only stores the current path, whereas BFS stores all nodes at a given depth level

When to Use BFS

BFS is a strong fit when you're focused on shortest-path problems in unweighted graphs. It systematically explores nodes in layers, making it ideal for use cases where the closest solution matters most:

  • Shortest path in unweighted graphs: Guarantees the fewest number of edges to a target node.
  • Level-order exploration: Visits nodes layer by layer from the starting point.
  • Range-limited search: Efficient for finding all nodes within a certain distance.

BFS is also well-suited to parallelization, since each layer of the graph can be processed independently.

Conclusion

DFS and BFS are the foundation of many graph-based algorithms, from simple pathfinding to advanced techniques like Dijkstra’s and A*. Understanding their behavior and knowing when to apply each allows you to design solutions that are both efficient and scalable. These traversal strategies aren’t just academic. They play a critical role in real-world systems across industries.

PuppyGraph makes it easy to explore your data through graph traversal, with built-in algorithms that run directly on your existing relational tables. No data migration required. Download the forever free PuppyGraph Developer Edition, or book a demo with our team to see how you can put these algorithms into practice.

Sa Wang is a Software Engineer with exceptional math abilities and strong coding skills. He earned his Bachelor's degree in Computer Science from Fudan University and has been studying Mathematical Logic in the Philosophy Department at Fudan University, expecting to receive his Master's degree in Philosophy in June this year. He and his team won a gold medal in the Jilin regional competition of the China Collegiate Programming Contest and received a first-class award in the Shanghai regional competition of the National Student Math Competition.

Sa Wang
Software Engineer

Sa Wang is a Software Engineer with exceptional math abilities and strong coding skills. He earned his Bachelor's degree in Computer Science from Fudan University and has been studying Mathematical Logic in the Philosophy Department at Fudan University, expecting to receive his Master's degree in Philosophy in June this year. He and his team won a gold medal in the Jilin regional competition of the China Collegiate Programming Contest and received a first-class award in the Shanghai regional competition of the National Student Math Competition.

No items found.
Join our newsletter

See PuppyGraph
In Action

See PuppyGraph
In Action

Graph Your Data In 10 Minutes.

Get started with PuppyGraph!

PuppyGraph empowers you to seamlessly query one or multiple data stores as a unified graph model.

Dev Edition

Free Download

Enterprise Edition

Developer

$0
/month
  • Forever free
  • Single node
  • Designed for proving your ideas
  • Available via Docker install

Enterprise

$
Based on the Memory and CPU of the server that runs PuppyGraph.
  • 30 day free trial with full features
  • Everything in Developer + Enterprise features
  • Designed for production
  • Available via AWS AMI & Docker install
* No payment required

Developer Edition

  • Forever free
  • Single noded
  • Designed for proving your ideas
  • Available via Docker install

Enterprise Edition

  • 30-day free trial with full features
  • Everything in developer edition & enterprise features
  • Designed for production
  • Available via AWS AMI & Docker install
* No payment required