Depth First Search (DFS) for Artificial Intelligence

Last Updated : 3 Sep, 2026

Depth-First Search (DFS) is a search and traversal algorithm used in Artificial Intelligence to explore tree and graph-like data structures.

  • Starts from the root or initial node and explores the deepest available node.
  • Backtracks when a node has no unexpanded successors.
  • Continues until the goal is found or all possible paths are explored.

Working

frame_3333
Search operation of the depth-first search
  • DFS starts at the root node and expands one branch as deeply as possible until it reaches a dead end. It then backtracks to the most recent unexplored node and explores its remaining successors. As shown in the above image, starting from node A, DFS explores B, then D. After reaching the dead end at D, it backtracks to B and explores E.
  • After completing the exploration of B, DFS backtracks to A and explores the remaining branch through C, followed by F and G. Once all nodes have been visited, the search terminates.

Key characteristics

  • Not Cost-Optimal: DFS is not cost-optimal because it does not guarantee finding the shortest path to the goal. It may find a solution quickly, but that path might not be the shortest or the cheapest one.
  • Stack-Based Search: DFS uses a stack to keep track of nodes to explore. It continues expanding the most recently added node and backtracks when it reaches a dead end.
  • Backtracking: DFS naturally uses backtracking to return to the most recent unexplored node and explore alternative paths. In backtracking-based problems, the algorithm generates one possibility at a time and abandons it when it cannot lead to a solution, reducing memory usage.

Edge classes in a Depth-first search tree based on a spanning tree

frame_3362
Edge classes in DFS based on spanning tree

The edges of the depth-first search tree can be divided into four classes based on the spanning tree, they are

  • Forward edges: The forward edge is responsible for pointing from a node of the tree to one of its successors.
  • Back edges: The back edge holds the power of directing its edge from a node of the tree to one of its ancestors.
  • Tree edges: When DFS explores the new vertex from the current vertex, the edge connecting them is called a tree edge. It is essential while constructing a DFS spanning tree because it represents the paths to be followed during the traversal.
  • Cross edges: Cross edges are the edges that connect two vertices that are neither ancestors nor descendants of each other in the DFS tree.

Depth First Search(DFS) Algorithm in Python

1. Initialization

The graph is stored as a dictionary (adjacency list).

Screenshot-2025-07-07-115536
Graph for this implementation

We also prepare:

  • A set visited to track visited nodes.
  • A list traversal_order to record the DFS path.
Python
# Define the graph as an adjacency list
graph = {
    'A': ['B', 'C'],
    'B': ['D', 'E'],
    'C': ['F'],
    'D': [],
    'E': [],
    'F': []
}

visited = set()           # To track visited nodes
traversal_order = []      # To store DFS traversal result

2. Define the DFS Function

This is a recursive DFS function:

  • If the node hasn't been visited: Mark it visited, add it to the result and recursively visit all unvisited neighbors
Python
def dfs(node):
    if node not in visited:
        visited.add(node)                 # Mark node as visited
        traversal_order.append(node)     

        for neighbor in graph[node]:     # Visit all neighbors
            dfs(neighbor)                

3. Start DFS Traversal from Node 'A'

We start DFS from node A. It will go as deep as possible before backtracking.

Python
dfs('A')

4. Final Traversal Order

This prints the final DFS order of visited nodes in a depth-first manner.

Python
print("\nFinal Traversal Order:")
print(" → ".join(traversal_order))

Output:

Final Traversal Order: A → B → D → E → C → F

You can download the complete code from here.

Example: DFS Implementation in Robotics Pathfinding

DFS can be used to find a path from a start node to a goal node in a maze or grid-based environment. The figure below shows the maze with the robot's initial state, obstacles and goal state. The goal is at (0,5).

Step 1: Define Maze dimensions and obstacles

maze_size represents the dimension of the maze, in our case, it's a 6x6 grid. A list of coordinates that represents the positions of obstacles within a maze is also specified. The robot is positioned at the initial state (0,0) and aims to reach the goal state (0,5).

frame_3334
Maze environment

Maze dimensions and obstacles

Python
# Maze dimensions and obstacles
maze_size = 6
obstacles = [(0,1),(1,1),(3,2),(3,3),(3,4),(3,5),(0,4),(4,1),(4,2),(4,3)]
start = (0,0)
goal = (0,5)

Step 2: Define a is_valid function

The is_valid function checks whether a given position of (x,y) is valid such that it inspects that it's within the bounds of the maze and not obstructed by any obstacles.

Python
def is_valid(x,y):
  return 0 <= x < maze_size and 0 <= y < maze_size and (x,y) not in obstacles

The dfs function recursively explores valid neighboring cells until it reaches the goal or exhausts all possible paths.

  • visited tracks explored cells to avoid revisiting them.
  • When the goal is reached, the current position is added to path and the function returns True.
  • During backtracking, each position is added to the path. If no path exists, the function returns False.
Python
def dfs (current, visited, path):
  x, y = current
  if current == goal:
    path.append(current)
    return True
  visited.add(current)
  moves = [(x-1,y), (x+1, y), (x, y-1), (x, y+1)]
  for move in moves:
    if is_valid(*move) and move not in visited:
      if dfs(move, visited, path):
        path.append(current)
        return True
  return False

Step 4: Call DFS function to find the path

Python
#Call DFS function to find the path
visited = set()
path = []
if dfs(start, visited, path):
  path.reverse()
  print("Path found:")
  for position in path:
    print(position)
else:
  print("No path found!")
    

Output:

Path found:
(0, 0)
(1, 0)
(2, 0)
(3, 0)
(3, 1)
(2, 1)
(2, 2)
(1, 2)
(0, 2)
(0, 3)
(1, 3)
(2, 3)
(2, 4)
(1, 4)
(1, 5)
(0, 5)

Output explanation

  • DFS starts from (0,0) and explores the maze by moving through valid neighboring cells. It backtracks whenever it reaches a dead end and continues until it reaches the goal at (0,5). The resulting path is then reversed and displayed from start to goal.
frame_3335-
Output representation

You can download the complete code from here.

Time & Space Complexity of DFS

The complexity of DFS depends on whether it is applied to an explicit graph or an implicit search tree.

Time Complexity

  • Explicit Graph: DFS visits each vertex and edge at most once, giving a time complexity of O(|V| + |E|), where V is the number of vertices and E is the number of edges.
  • Implicit Search Tree: For a search tree with branching factor b and maximum depth d, the time complexity is O(bᵈ).

Space Complexity

  • Explicit Graph: DFS requires O(|V|) space to store visited vertices and the stack or recursion stack.
  • Implicit Search Tree: The space complexity is O(bd), as DFS mainly stores the nodes along the current search path and their unexplored alternatives.

Applications of DFS in AI

  • Maze Generation: DFS can generate mazes by randomly exploring unvisited neighboring cells and removing walls between them until the maze is complete.
  • Puzzle Solving: DFS explores different combinations of possible solutions in puzzles such as Japanese nonograms.
  • Robotics Pathfinding: DFS can find paths in maze or grid-based environments, especially when simplicity and memory efficiency are important.
Comment

Explore