Computer scienceProgramming languagesJavaInterview preparationAlgorithms and problem solving techniques

Graph traversal: DFS vs BFS

7 minutes read

As you may recall, graphs are an integral part of programming. They can be used to represent complex data structures simply and intuitively, making them easier to understand and analyze. However, to analyze a graph, we must first gain access to every element. This is where traversal algorithms come into play. These algorithms allow us to traverse a given graph efficiently and manipulate the data stored within it. But how exactly do these algorithms work? Let's answer this question by analyzing the two most popular methodologies used by programmers: Depth-First Search (DFS) and Breadth-First Search (BFS).

Depth-First Search (DFS) is an algorithm for traversing or searching tree or graph data structures. The algorithm starts at the root node (or an arbitrary node of a graph, sometimes referred to as a "search key") and explores as far as possible along each branch before backtracking. DFS employs a stack data structure to keep track of the next vertex to explore. This comes into play when the algorithm reaches a dead end during any iteration.

Here's a more detailed explanation of how DFS works:

  1. Start by pushing the graph's root node onto the stack.
  2. Pop the top node from the stack and mark it as visited.
  3. Create a list of that vertex's adjacent nodes. Push the ones that have not yet been visited onto the stack.
  4. Repeat steps 2 and 3 until the stack is empty.

DFS is particularly useful in scenarios where you want to visit every node in the graph, and the order in which the nodes are visited is important. It is commonly employed in scenarios such as finding the connected components of a graph, pathfinding for games, detecting cycles in graphs, and many others.

The time complexity of DFS is O(V+E)O(V+E), where VV is the number of vertices and EE is the number of edges in the graph. This is because, like BFS, you will visit each vertex and each edge exactly once. The space complexity of DFS is also O(V+E)O(V+E), as, in the worstcase scenario, you may need to store all vertices and edges in the stack.

One important aspect to note about DFS is its tendency to get caught in an infinite loop when dealing with cycles. To avoid this, one can employ a boolean visited array. If we revisit a node that we've already marked as visited, we can terminate the traversal and conclude that the graph contains a cycle.

DFS also has a variant known as Depth-Limited Search, where the depth (or the number of edges from the start node) is limited to a specified value. This can be useful in scenarios where the graph is large and you want to limit the search to a certain depth.

In conclusion, DFS is a highly useful and versatile algorithm that's widely used in both theoretical computer science and practical programming applications. Its ability to traverse the entire graph using a simple stack-based approach makes it a popular choice for solving many types of problems.

Breadth-First Search (BFS) is a graph traversal algorithm that explores nodes in a graph in breadthward motion. It uses a queue to remember the next vertex from which to start a search when a dead end occurs in any iteration. This algorithm traverses or searches a graph in a breadthward manner, meaning it first explores all the nodes at the current level before moving on to nodes at the next level.

BFS begins traversal from the root node (or any arbitrary node in the case of a disconnected graph) and visits nodes in a level-by-level manner, visiting nodes that are at an increasing distance from the start. It does so by discovering all vertices at distance kk from the starting point before discovering vertices at distance k+1k+1.

To implement BFS, a queue data structure is typically employed. This is because a queue follows the First-In-First-Out (FIFO) principle, ensuring that nodes are explored in the order in which they are inserted in the queue. Here's how BFS works:

  1. Start by putting any one of the graph's vertices at the back of a queue.
  2. Take the front item from the queue and add it to the visited list.
  3. Create a list of that vertex's adjacent nodes. Add the ones that aren't in the visited list to the back of the queue.
  4. Keep repeating steps 2 and 3 until the queue is empty.

The time complexity of BFS is O(V+E)O(V+E), where VV is the number of vertices and EE is the number of edges in the graph. This is because, in the worst case, you will visit each vertex and each edge exactly once. The space complexity of BFS is also O(V+E)O(V+E), as in the worst case, you may need to store all vertices and edges in the queue.

BFS is particularly useful for finding the shortest path in unweighted graphs and for solving problems such as the "Six Degrees of Kevin Bacon," where the objective is to find the shortest path between two actors by hopping through the movies in which they've starred. It is also employed for testing for bipartiteness—that is, whether a graph can be divided into two sets of nodes such that no nodes from the same set are adjacent.

In conclusion, BFS is a powerful and versatile algorithm that is widely used in both theoretical computer science and practical programming applications. Its ability to find the shortest path in unweighted graphs and its suitability for parallel algorithms make it a popular choice for solving a wide array of problems.

Cycle detection using DFS

One of the common challenges in graph theory is cycle detection. A cycle is defined as a path that starts and ends at the same vertex. To introduce the concept of cycle detection in a graph, we could say it involves determining whether a given graph contains a cycle.

Depth-First Search (DFS) is a widely used algorithm for traversing graphs, and it can also be adapted for cycle detection. The fundamental idea behind this algorithm is to mark each visited vertex while keeping track of the vertices in the current recursion stack. If we encounter a vertex that is both marked and present in the current recursion stack, then a cycle exists in the graph.

The algorithm for cycle detection using DFS can be summarized in the following steps:

  1. Initialize all vertices as unvisited.
  2. For each unvisited vertex, call the DFS function.
  3. In the DFS function, mark the current vertex as visited and add it to the recursion stack.
  4. For each adjacent vertex, if it is not visited, call the DFS function recursively.
  5. If the adjacent vertex is already visited and present in the recursion stack, then a cycle exists in the graph.

The time complexity of this cycle detection algorithm using DFS is O(V+E)O(V+E), where VV is the number of vertices and EE is the number of edges in the graph.

To illustrate the cycle detection process, consider the following example. Assume we have a graph with five vertices and six edges, organized as follows:

A --> B

B --> C

C --> D

D --> E

E --> B

B --> A

a graph with five vertices and six edges

Starting from vertex A, we can perform DFS and detect a cycle using these steps:

  1. Visit vertex A and add it to the recursion stack.
  2. Visit vertex B and add it to the recursion stack.
  3. Visit vertex C and add it to the recursion stack.
  4. Visit vertex D and add it to the recursion stack.
  5. Visit vertex E and add it to the recursion stack.
  6. Visit vertex B, which is already in the recursion stack; hence, a cycle exists in the graph.

In conclusion, DFS-based cycle detection is a valuable tool for identifying cycles in graphs. With a time complexity of O(V+E)O(V+E), it is applicable to various real-world scenarios, including network and social network analysis.

Chess knight problem

The chess knight problem is a classic puzzle that involves moving a knight across a chessboard from one square to another, utilizing its unique L-shaped moves. The goal is to find the shortest path between the starting and destination squares while avoiding obstacles.

chess knight graph

To address this problem, we can employ a Breadth-First Search (BFS) algorithm. This approach explores all potential moves from the starting square in a systematic way. It also tracks the distance from the starting square to each visited square. Once the destination square has been reached, the shortest path can be identified by retracing the steps from the destination back to the starting square.

The algorithm for solving the chess knight problem using BFS can be summarized as follows:

  1. Initialize a queue with the starting square, setting its distance from the starting square to zero.
  2. While the queue is not empty, dequeue the front square and its associated distance.
  3. For each possible move originating from the current square, calculate its distance from the starting square and enqueue it if it has not already been visited.
  4. If the destination square is reached, return the distance from the starting square to the destination square.

The time complexity of the algorithm is O(N2)O(N^2), where NN is the dimension of the chessboard. This is because each square can be visited at most once. Similarly, the space complexity is also O(N2)O(N^2) due to the potential for storing up to N2N^2 squares in the queue.

For instance, to find the shortest path from square A1 to H8 on an 8x8 chessboard, BFS can be used to explore all viable moves starting from A1. The distance to each visited square from A1 is recorded. Once the square H8 is reached, we can retrace our steps from H8 back to A1 to find the shortest path.

DFS vs BFS

When comparing DFS and BFS, several key characteristics set them apart. DFS is a search algorithm that explores as far as possible along each branch before backtracking. In contrast, BFS explores all neighboring nodes at the current depth before moving on to nodes at the next level.

One advantage of DFS is its lower memory requirement compared to BFS. This is because DFS only needs to store the path from the starting node to the current node. However, this can also make DFS susceptible to infinite loops when the graph contains cycles. BFS, on the other hand, guarantees the discovery of the shortest path but requires more memory since it stores all nodes at each level.

In scenarios where finding the shortest path is not a priority and memory is limited, DFS may be the better option. Conversely, when the shortest path is crucial and memory is not a significant constraint, BFS is generally preferable.

Overall, it is important to consider the specific requirements of the problem at hand when deciding which algorithm to use. Each algorithm has its strengths and weaknesses, and choosing the right one can make all the difference in finding the optimal solution.

Conclusion

In summary, we've explored two primary methods used for graph traversal: BFS and DFS algorithms, along with their differences. Here's what we've learned:

  • Graph traversal algorithms like Depth-First Search (DFS) and Breadth-First Search (BFS) are vital for efficiently navigating and manipulating data in graphs and trees.
  • DFS employs a recursive approach and backtracks to explore all nodes along a path. This makes it memory-efficient but prone to infinite loops when the graph contains cycles.
  • BFS explores all nodes at the current level before progressing to the next level. This ensures the discovery of the shortest path but demands more memory to store nodes at each level.
  • Cycle detection in a graph can be achieved using DFS by marking visited nodes and tracking the recursion stack. This method provides a time complexity of O(V+E)O(V+E), where VV is the number of vertices and EE is the number of edges.
  • The chess knight problem can be solved using BFS to find the shortest path between two squares on a chessboard, with a time and space complexity of O(N2)O(N^2), where NN is the size of the chessboard.
  • The choice between DFS and BFS depends on the specific problem requirements: DFS is suitable when memory is limited and finding the shortest path is not crucial, while BFS is preferable when finding the shortest path is essential and memory is less of a concern.
7 learners liked this piece of theory. 0 didn't like it. What about you?
Report a typo