Master DFS - Depth-First Search

Learn Depth-First Search with interactive visualizations. Explore graphs deeply using stack-based traversal. Master pathfinding, cycle detection, and topological sorting.

O(V + E) Time
Stack-Based
Deep Exploration
🔍
Deep First
↩️
Backtracking
🔄
Cycle Detection
📊
Topological Sort
Powered by orbit2x.com

DFS Visualization

Live
Depth: 0
Visited: 0
Ready to traverse

Select an example graph to visualize

Choose from sample graphs below

Unvisited
Exploring
Visited
Active Edge

Call Stack (LIFO) Size: 0

Stack empty

Graph Input & Controls

Code Implementation

def dfs_recursive(graph, node, visited=None):
    """
    Recursive Depth-First Search
    Time: O(V + E) - visit each vertex and edge once
    Space: O(V) - recursion stack + visited set
    """
    if visited is None:
        visited = set()

    visited.add(node)
    print(f"Visiting node: {node}")

    # Explore all neighbors
    for neighbor in graph[node]:
        if neighbor not in visited:
            dfs_recursive(graph, neighbor, visited)

    return visited

def dfs_iterative(graph, start):
    """
    Iterative DFS using explicit stack
    """
    visited = set()
    stack = [start]

    while stack:
        node = stack.pop()  # LIFO - depth-first

        if node not in visited:
            visited.add(node)
            print(f"Visiting node: {node}")

            # Add neighbors to stack (reverse for same order as recursive)
            for neighbor in reversed(graph[node]):
                if neighbor not in visited:
                    stack.append(neighbor)

    return visited

# Usage example
graph = {
    0: [1, 2],
    1: [3, 4],
    2: [5],
    3: [],
    4: [],
    5: []
}

print("Recursive DFS:")
dfs_recursive(graph, 0)  # Output: 0 -> 1 -> 3 -> 4 -> 2 -> 5

print("\nIterative DFS:")
dfs_iterative(graph, 0)  # Same output

Big O Complexity

Time O(V + E)

Visit each vertex and edge once

Space O(V)

Stack depth + visited tracking

Current Action
Ready to traverse
Stack State
Empty

DFS Properties

🔍
Depth-First

Explores as far as possible before backtracking

📚
Stack-Based

Uses recursion stack or explicit stack structure

🎯
Memory Efficient

O(V) space for deep graphs vs BFS's O(V) queue

Statistics

Nodes Visited 0
Edges Explored 0
Max Depth 0
Backtracks 0

Did You Know?

DFS is used in topological sorting for task scheduling

Cycle detection in graphs relies on DFS backtracking

Maze solving algorithms often use DFS with backtracking

DFS is more memory-efficient than BFS for deep graphs

DFS Applications

Depth-First Search is fundamental to many graph algorithms and real-world problem-solving scenarios.

🎯

Pathfinding

Find paths between nodes in graphs, mazes, and game maps. DFS explores deeply before backtracking.

Maze solving
Game AI navigation
🔄

Cycle Detection

Detect cycles in directed and undirected graphs using gray node marking during traversal.

Deadlock detection
Dependency analysis
📊

Topological Sorting

Order tasks with dependencies using DFS finish times. Essential for build systems and schedulers.

Task scheduling
Build systems
🌐

Connected Components

Find all connected subgraphs in an undirected graph. Useful for network and social graph analysis.

Network clusters
Social communities
🔗

SCCs (Kosaraju's)

Find strongly connected components in directed graphs using two DFS passes for cycle groups.

Web crawlers
Recommendation systems
🌲

Tree Traversals

DFS enables preorder, inorder, and postorder tree traversals for expression evaluation and serialization.

Expression trees
File system traversal

DFS vs BFS

Use DFS when: You need to explore deeply, detect cycles, or perform topological sorting.

Use BFS when: You need shortest paths, level-order traversal, or breadth exploration.

Memory: DFS uses O(h) space for stack depth, BFS uses O(w) for queue width.

Path length: BFS finds shortest paths, DFS may find longer paths first.

Learn Depth-First Search (DFS) Algorithm: Interactive Tutorial with Visualization

Master DFS algorithm with step-by-step visualization, code examples in Python, JavaScript, Java, and C++. Understand graph traversal, backtracking, cycle detection, and topological sorting with interactive animations. Perfect for coding interviews, competitive programming, and computer science students.

What Is Depth-First Search Algorithm?

Depth-First Search (DFS) is a fundamental graph traversal algorithm that explores as far as possible along each branch before backtracking. DFS uses a stack data structure (either explicit or via recursion) to remember vertices to visit next, achieving O(V + E) time complexity where V is vertices and E is edges. According to Wikipedia's DFS article, this algorithm was first investigated by French mathematician Charles Pierre Trémaux in the 19th century as a strategy for solving mazes.

Unlike Breadth-First Search (BFS) which explores level-by-level, DFS dives deep into one path before exploring alternatives. This makes DFS ideal for pathfinding, cycle detection, topological sorting, maze solving, and solving puzzles like Sudoku. DFS is crucial for technical interviews at companies like Google, Amazon, Facebook, and Microsoft—appearing in 40% of algorithm questions according to LeetCode interview patterns.

Why Learn DFS Algorithm?

Interview Success
  • Top coding interview topic: 40% of graph problems use DFS
  • LeetCode essential: 200+ DFS problems to practice
  • FAANG favorite: Asked by Google, Amazon, Microsoft, Meta
  • Foundation for advanced algorithms: Tarjan's, Kosaraju's, backtracking
Real-World Applications
  • Web crawling: Search engines traverse web pages depth-first
  • Dependency resolution: Build systems, package managers
  • Maze solving: Robotics, game AI pathfinding algorithms
  • Network analysis: Finding connected components, bridges

DFS vs BFS: When to Use Which?

✓ Use DFS When:
  • • Finding path (not shortest path)
  • • Detecting cycles in graphs
  • • Topological sorting
  • • Solving puzzles with backtracking
  • • Memory is limited (O(h) vs O(w))
✓ Use BFS When:
  • • Finding shortest path in unweighted graph
  • • Level-order traversal needed
  • • Finding all nodes within k distance
  • • Social network friend recommendations
  • • GPS navigation shortest routes

How Does DFS Algorithm Work? (Step-by-Step)

1
Start at source node: Begin traversal from a starting vertex (usually node 0 or specified root). Mark the start node as visited to avoid revisiting and add it to the call stack for processing. This initialization step sets up the recursion or explicit stack for the traversal.
2
Explore first unvisited neighbor: From the current node, select the first unvisited adjacent node. DFS prioritizes depth over breadth—always choosing to go deeper before exploring siblings. This creates the characteristic deep traversal path before backtracking.
3
Recursively visit neighbors: Repeat the process for each unvisited neighbor, going as deep as possible. Each recursive call adds a new frame to the call stack. Track visited nodes using a hash set or boolean array to prevent infinite loops in cyclic graphs.
4
Backtrack when stuck: When a node has no unvisited neighbors, backtrack to the previous node on the stack. This unwinding process pops the call stack and returns to the parent node. Backtracking is what makes DFS perfect for maze solving and puzzle problems.
5
Continue until all nodes visited: Repeat steps 2-4 until all reachable nodes are visited. For disconnected graphs, restart DFS from unvisited nodes to explore all components. Final complexity: O(V + E) time, O(V) space for recursion stack.

💡 Pro Tip: Recursive vs Iterative DFS

Recursive DFS is cleaner and easier to code (5 lines) but risks stack overflow for deep graphs (10,000+ depth). Iterative DFS with explicit stack handles any depth safely and gives you precise control over traversal order. Use recursive for interviews (cleaner code), iterative for production systems (safer). Our stack tutorial explains both approaches.

DFS Time and Space Complexity Explained

O
Time Complexity: O(V + E)

DFS visits each vertex V exactly once and explores each edge E once (twice for undirected graphs). For adjacency list representation, checking neighbors is O(1) per edge. Total: O(V) for visiting + O(E) for edge exploration = O(V + E). Example: graph with 100 nodes and 300 edges requires 400 operations maximum. Learn more about DFS time complexity analysis.

O
Space Complexity: O(V)

Recursive DFS uses call stack space proportional to maximum depth: O(h) where h is height. Worst case (linear graph): h = V, so O(V). Best case (balanced tree): h = log(V), so O(log V). Iterative DFS uses explicit stack: O(V) worst case. Additional O(V) for visited set. Total space: O(V) for stack + O(V) for visited = O(V). Memory-efficient compared to BFS's O(V) queue for wide graphs.

Performance Optimization Tips

Use adjacency list (not matrix) for sparse graphs to achieve O(V + E). Mark nodes visited immediately to prevent redundant checks. For dense graphs (E ≈ V²), time becomes O(V²). Pre-allocate visited array instead of hash set for 2x speedup in practice. Iterative DFS avoids function call overhead—5-10% faster than recursive in benchmarks. See our complexity calculator for custom analysis.

10 Real-World DFS Algorithm Applications

1. Maze Solving and Pathfinding

DFS finds paths through mazes by exploring each direction until hitting dead ends, then backtracking. Used in robotics navigation, game AI (Pac-Man ghosts, dungeon exploration), and route planning. While not guaranteed to find shortest path, DFS requires less memory than BFS—critical for embedded systems. Try our distance calculator for path metrics.

LeetCode Problems: #79 Word Search, #200 Number of Islands, #1254 Number of Closed Islands

2. Cycle Detection in Directed Graphs

DFS detects cycles using three node states: white (unvisited), gray (in-progress), black (finished). Back edge to gray node = cycle found. Applications: deadlock detection in operating systems, circular dependency checking in build systems (Maven, Gradle), detecting infinite loops in program control flow. Essential for compilers and package managers.

LeetCode Problems: #207 Course Schedule, #802 Find Eventual Safe States

3. Topological Sorting

DFS-based topological sort orders tasks with dependencies for execution (finish time in reverse order). Used in task scheduling, build systems (compile order for source files), course prerequisite planning, and Makefile dependency resolution. Only works on Directed Acyclic Graphs (DAGs)—DFS detects cycles first. Critical for CI/CD pipelines and project management tools.

LeetCode Problems: #210 Course Schedule II, #269 Alien Dictionary

4. Connected Components in Graphs

DFS finds all disconnected subgraphs by running from each unvisited node. Applications: social network friend clusters, image segmentation in computer vision, network partition detection, and clustering analysis. Used by Facebook for friend suggestions and by image editors for flood fill tools. Check our network analysis tools.

LeetCode Problems: #547 Number of Provinces, #323 Number of Connected Components

5. Strongly Connected Components (Tarjan's Algorithm)

DFS finds maximal subgraphs where every node reaches every other node using discovery time and low-link values. Applications: web page ranking, compiler optimization (identifying independent code blocks), circuit design verification. Tarjan's SCC runs in single O(V + E) DFS pass—highly efficient.

LeetCode Problems: #1192 Critical Connections in a Network

6. Backtracking Problems (N-Queens, Sudoku)

DFS explores all solution possibilities with constraint checking and backtracking. Solves N-Queens, Sudoku, permutations, combinations, subset generation, and constraint satisfaction problems. DFS tries each possibility, backtracks on invalid states—exponential O(b^d) complexity but finds all solutions. Used in puzzle solvers and combinatorial optimization.

LeetCode Problems: #51 N-Queens, #37 Sudoku Solver, #46 Permutations, #78 Subsets

7. Finding Bridges and Articulation Points

DFS identifies critical edges/nodes whose removal disconnects the graph. Bridges: edges that disconnect graph when removed. Articulation points: vertices that disconnect graph when removed. Applications: network reliability analysis, finding single points of failure in infrastructure, Internet backbone resilience testing. Uses discovery time and low-link in single DFS pass.

Used in: Network infrastructure planning, telecom systems, power grid analysis

8. Expression Tree Evaluation

DFS traverses mathematical expression trees in post-order to evaluate formulas. Used in compilers for abstract syntax tree (AST) evaluation, calculator applications, and formula parsers. DFS naturally handles operator precedence through tree structure. Check our calculator tool for expression evaluation.

LeetCode Problems: #150 Evaluate Reverse Polish Notation, #224 Basic Calculator

9. Web Crawling and Site Mapping

Search engines use DFS to crawl websites by following links depth-first before backtracking. Discovers deeply nested pages faster than BFS. Used by Google, Bing for indexing, sitemap generation tools, and broken link checkers. DFS is memory-efficient for deep website hierarchies with millions of pages. Combine with our SSL checker for secure crawling.

Real usage: Googlebot, Screaming Frog SEO Spider, Sitemap XML generators

10. Game AI and Decision Trees

DFS explores game state trees for AI decision-making in chess, checkers, tic-tac-toe. Combined with minimax algorithm and alpha-beta pruning, DFS evaluates millions of future moves. Used in video game NPCs for pathfinding and strategy planning. Modern game engines use iterative deepening DFS (IDDFS) to balance memory and optimality.

Used in: Chess engines (Stockfish), Go AI (AlphaGo early versions), game tree search

7 Common DFS Implementation Mistakes to Avoid

1. Forgetting to Mark Nodes as Visited

Not tracking visited nodes causes infinite loops in cyclic graphs. Always use a visited set/array and mark nodes BEFORE recursing to neighbors. This mistake appears in 30% of failed interview solutions. Mark visited in the parent call, not after returning from recursion.

2. Not Handling Disconnected Graphs

Single DFS call only reaches connected components. For disconnected graphs, loop through all nodes and start DFS from unvisited ones. This finds all components—critical for problems like #323 Number of Connected Components. Check if (node not visited) before each DFS call.

3. Stack Overflow in Deep Recursion

Python default stack limit is ~1000 recursion depth; C++ varies by compiler. Deep graphs cause stack overflow. Use iterative DFS with explicit stack for production code, or increase stack size with sys.setrecursionlimit() (Python). Iterative DFS handles graphs with millions of nodes safely.

4. Incorrect Cycle Detection Logic

Cycle detection requires three states (white/gray/black), not just visited boolean. Back edge to gray (in-progress) node = cycle. Checking only visited gives false positives in directed graphs. Learn proper cycle detection patterns.

5. Confusing DFS with BFS Use Cases

DFS doesn't guarantee shortest path—use BFS for that. DFS is for pathfinding (any path), topological sort, cycle detection, backtracking. Using DFS for shortest path in unweighted graphs fails 50% of test cases. Know when to use our BFS tutorial instead.

6. Not Handling Self-Loops and Multi-Edges

Self-loops (node → itself) need special handling to avoid counting as cycles. Multi-edges (parallel edges between same nodes) require edge-based visited tracking, not just node-based. Check edge cases: empty graph, single node, fully disconnected graph (no edges).

7. Inefficient Graph Representation

Adjacency matrix (V × V array) wastes O(V²) space for sparse graphs and slows DFS to O(V²). Use adjacency list for O(V + E) time. For edge-list representation, build adjacency list first. HashMap vs array for neighbors: array is 2x faster but requires contiguous node IDs.

Interactive DFS Visualization Features

Our visualizer helps you understand DFS algorithm through step-by-step animation and real-time code execution:

🎯 Step-by-Step Animation

Watch DFS traverse graphs node-by-node with highlighted edges, stack visualization, and depth tracking. Pause, resume, and step through at your own pace. Adjust animation speed from slow (2s/step) to fast (0.4s/step) to match your learning style.

📊 8 Pre-Built Graph Examples

Explore simple trees, binary trees, cyclic graphs, DAGs, disconnected graphs, complete graphs, linear paths, and maze grids. Each example demonstrates different DFS behaviors and edge cases you'll encounter in interviews and real projects.

💻 Code in 4 Languages

See complete DFS implementations in Python, JavaScript, Java, and C++ side-by-side. Copy-paste ready code with comments. Compare recursive vs iterative approaches. Perfect for interview prep—practice in your preferred language.

🔍 Real-Time Stats Dashboard

Track nodes visited, edges explored, current depth, backtrack count, and complexity metrics in real-time. Understand how O(V + E) plays out with actual numbers. See stack state at each step to visualize LIFO behavior.

🎓 Complexity Analysis

Learn time and space complexity with interactive explanations. Compare DFS with BFS, Dijkstra's, and A* algorithms. See how graph structure affects performance—sparse vs dense graphs, trees vs cyclic graphs.

🚀 Interview Practice Mode

Test your understanding by predicting traversal order before running animation. Practice common interview variations: path finding, cycle detection, topological sort. Link to 50+ LeetCode problems for further practice.

DFS Algorithm Frequently Asked Questions

What is the difference between DFS and BFS?

DFS explores depth-first using a stack (LIFO), going deep before backtracking. BFS explores breadth-first using a queue (FIFO), visiting all neighbors before going deeper. DFS: O(h) space, doesn't guarantee shortest path. BFS: O(w) space, finds shortest path in unweighted graphs. Use DFS for topological sort, cycle detection; BFS for shortest paths. Both have O(V + E) time. Learn more in our BFS tutorial.

When should I use recursive vs iterative DFS?

Recursive DFS is cleaner (5-10 lines) and natural for interviews—easier to code under pressure. However, it risks stack overflow for graphs deeper than 1,000-10,000 nodes (varies by language). Iterative DFS with explicit stack handles any depth safely, gives precise control over traversal order, and is 5-10% faster (no function call overhead). Use recursive for interviews/small graphs, iterative for production systems.

How do I detect cycles using DFS?

Cycle detection requires three node states: white (unvisited), gray (currently being explored), black (finished). During DFS, if you encounter a gray node (ancestor in current path), you've found a back edge = cycle exists. For undirected graphs, also check if neighbor is not the parent node to avoid false positives. This pattern appears in 40% of graph interview problems. See cycle detection algorithms.

What is the space complexity of DFS and why?

DFS space complexity is O(h) where h is maximum depth, or O(V) worst case for linear graphs. Recursive DFS uses call stack; each recursion level adds a frame. Worst case: single path from start to end node (V deep). Best case: balanced binary tree (log V deep). Additional O(V) for visited set brings total to O(V). This is why DFS is more memory-efficient than BFS for deep, narrow graphs but uses similar space for wide graphs.

Can DFS find the shortest path in a graph?

No, DFS does not guarantee shortest path in unweighted graphs—it finds any path. DFS explores one direction fully before trying alternatives, potentially finding a long path before a shorter one. For shortest path in unweighted graphs, use BFS. For weighted graphs, use Dijkstra's algorithm or A*. DFS is for path existence checks, topological sort, cycle detection, not optimal pathfinding.

How does DFS handle disconnected graphs?

Single DFS call only explores one connected component. For disconnected graphs (multiple separate subgraphs), loop through all vertices and start DFS from each unvisited node. This finds all components: count = number of DFS calls needed. Pattern: for node in graph: if not visited[node]: dfs(node); components++. Used in problems like #323 Number of Connected Components, #547 Number of Provinces.

What are common DFS interview questions?

Top 10 DFS interview problems: 1. #200 Number of Islands (connected components), 2. #207 Course Schedule (cycle detection), 3. #210 Course Schedule II (topological sort), 4. #79 Word Search (backtracking), 5. #133 Clone Graph, 6. #547 Number of Provinces, 7. #733 Flood Fill, 8. #797 All Paths Source to Target, 9. #1192 Critical Connections, 10. #51 N-Queens (backtracking). Practice on LeetCode DFS tag.

How do I implement topological sort using DFS?

DFS topological sort: run DFS on all nodes, track finish times (when all neighbors explored), then sort nodes by decreasing finish time. Alternatively, push nodes to stack after visiting all neighbors—pop stack for topological order. Only works on DAGs (Directed Acyclic Graphs); detect cycles first. Applications: task scheduling, build systems, course prerequisites. See our interactive example above for step-by-step visualization of topological sorting.

Related Algorithm Tutorials & Tools

Master data structures and algorithms with our complete interactive learning platform:

Start Learning DFS Algorithm Now

Master Depth-First Search with interactive visualizations, code examples in 4 languages, and step-by-step tutorials. Perfect for coding interviews, competitive programming, and computer science courses. 100% free, no signup required.

Interactive Visualizations
8 Graph Examples
Code in 4 Languages
Interview Practice

Trusted by 100,000+ students and developers learning algorithms and data structures