DEV Community

Khushi
Khushi

Posted on • Edited on

Depth-First Search

🔁Quick BFS Recap

  • In Breadth-First Search (BFS), you explore the graph level by level.
  • You visit all immediate neighbors first, then move on to their neighbors, and so on.
  • Uses a queue (FIFO)
  • Best for shortest path in unweighted graphs
  • Real-life: friend suggestions, web crawling, peer-to-peer networks

Now, Let’s Dive into DFS – Depth-First Search

  • No more level-by-level. It’s time to go DEEP!
  • In DFS, you pick a path and go as deep as possible, only backtracking when there’s nowhere left to go.

Let's Imagine this,

You enter a maze and just keep walking forward till you hit a dead-end, then backtrack and explore the next path.

It Uses recursion or a stack and best for the Exploring complete paths, Detecting cycles, Maze solving, Topological sort.

What is DFS?
Depth-First Search (DFS) is a classic graph traversal algorithm.
Instead of exploring layer by layer like BFS, it dives deep into each branch of a graph or tree before backtracking.

How It Works:

1.Start from a source node

  • Choose a node to begin with (say, node 0).
  • This will be the root of your traversal.

2.Use a stack (or recursion) to track the path

  • DFS relies on a stack data structure.
  • You can either explicitly use a stack or let recursion handle it for you (since function calls internally use a call stack).

3.Maintain a visited[] array

  • To avoid infinite loops (especially in cyclic graphs), keep track of nodes you’ve already visited.
  • This ensures each node is processed only once.

4.Process nodes deeply before backtracking

  • Visit the current node and mark it as visited.
  • Then, move to its first unvisited neighbor.
  • Continue this process until there are no unvisited neighbors left.
  • When stuck, backtrack to the most recent node that still has unvisited neighbors, and repeat.

🧠 Graph Structure (Adjacency List based on the image):
From the graph:
1: [2, 3]
2: [1, 4]
3: [1, 5]
4: [2, 5]
5: [3, 4]

We’ll assume:
It’s an undirected graph.

Step 1

  • Start DFS at 1.
  • Mark 1 as visited → Visited = [1].
  • Explore first neighbor → 2.

Step 2

  • At node 2.
  • Mark 2 as visited → Visited = [1, 2].
  • Explore first neighbor → 4.

Step 3

  • At node 4.
  • Mark 4 as visited → Visited = [1, 2, 4].
  • Neighbors of 4 = (2, 5).
    • 2 already visited → skip.
    • Move to neighbor 5.

Step 4

  • At node 5.
  • Mark 5 as visited → Visited = [1, 2, 4, 5].
  • Neighbors of 5 = (3, 4).
    • 4 already visited → skip.
    • Next is 3.

Step 5

  • At node 3.
  • Mark 3 as visited → Visited = [1, 2, 4, 5, 3].
  • Neighbors of 3 = (1, 5). Both already visited → backtrack.

Step-by-Step (Recursive DFS)
Start at 1, mark visited → dfs = [1]
Go to neighbor 2 (first unvisited of 1) → dfs = [1, 2]
Go to neighbor 4 (from 2) → dfs = [1, 2, 4]
Go to neighbor 5 (from 4) → dfs = [1, 2, 4, 5]
Go to neighbor 3 (from 5) → dfs = [1, 2, 4, 5, 3]
All neighbors visited. Backtrack until all paths are done.

🔄 Final DFS Traversal Order:
1 → 2 → 4 → 5 → 3

DFS Code in C++

#include <iostream> #include <vector> using namespace std; // Helper method to perform DFS recursively void dfsHelper(int node, vector<int> adj[], vector<bool>& visited, vector<int>& dfs) { visited[node] = true; dfs.push_back(node); for (int neighbor : adj[node]) { if (!visited[neighbor]) { dfsHelper(neighbor, adj, visited, dfs); } } } // DFS function that calls the helper vector<int> dfsOfGraph(int V, vector<int> adj[]) { vector<int> dfs; vector<bool> visited(V, false); dfsHelper(0, adj, visited, dfs); // starting from node 0 return dfs; } int main() { int V = 5; vector<int> adj[V]; // 1-2, 1-3, 2-4, 3-5, 4-5 adj[0] = {1, 2}; // node 1 -> 2, 3 adj[1] = {0, 3}; // node 2 -> 1, 4 adj[2] = {0, 4}; // node 3 -> 1, 5 adj[3] = {1, 4}; // node 4 -> 2, 5 adj[4] = {2, 3}; // node 5 -> 3, 4 vector<int> result = dfsOfGraph(V, adj); cout << "DFS Traversal: "; for (int node : result) cout << node + 1 << " "; cout << endl; return 0; } 
Enter fullscreen mode Exit fullscreen mode

⏱ Time Complexity → O(V + E)

  • V (Vertices):

    • Every vertex is visited exactly once.
    • Visiting a node + marking as visited = O(1) each → overall O(V).
  • E (Edges):

    • For every node, DFS explores its adjacency list (all connected edges).
    • Across the whole graph, each edge is checked at most twice (once from each endpoint in an undirected graph, once in a directed graph).
    • Total edge exploration = O(E).

So, the total time = O(V + E).

Space Complexity → O(V)
DFS requires memory for:

  • Visited array → To keep track of visited nodes (size = V).
  • Recursion stack (or explicit stack) →
  • In the worst case (graph shaped like a linked list), recursion depth can go up to V.

So, maximum call stack size = O(V).

Top comments (0)