Back to Welcome Page

Module 4: Graphs IV

Advanced graph traversal techniques with depth-first traversal

Module Objectives

Upon completion of this module you will be able to:

Depth-First Traversal (DFT)

Understanding Depth-First Traversal

Depth-First Traversal (DFT) is a graph traversal algorithm that explores as far as possible along each branch before backtracking. It uses the principle of recursion and backtracking or a stack data structure for its implementation.

Key Characteristics of DFT:

Graph Representation

Before implementing DFT, we need a way to represent our graph. Common representations include:

// Adjacency List representation class Graph { constructor() { this.adjacencyList = {}; } addVertex(vertex) { if (!this.adjacencyList[vertex]) { this.adjacencyList[vertex] = []; } } addEdge(vertex1, vertex2) { this.adjacencyList[vertex1].push(vertex2); // For undirected graph, add the reverse edge too // this.adjacencyList[vertex2].push(vertex1); } }

Recursive DFT Implementation

The recursive approach to DFT leverages the call stack to keep track of vertices to visit:

// Recursive DFT implementation class Graph { // ... previous methods from above ... depthFirstTraversalRecursive(startVertex) { const result = []; const visited = {}; const adjacencyList = this.adjacencyList; // Helper function to conduct DFT recursively function dfs(vertex) { if (!vertex) return null; // Mark vertex as visited visited[vertex] = true; // Add vertex to result result.push(vertex); // Visit each neighbor adjacencyList[vertex].forEach(neighbor => { if (!visited[neighbor]) { return dfs(neighbor); } }); } // Start DFT from startVertex dfs(startVertex); return result; } } // Example usage const g = new Graph(); g.addVertex("A"); g.addVertex("B"); g.addVertex("C"); g.addVertex("D"); g.addVertex("E"); g.addVertex("F"); g.addEdge("A", "B"); g.addEdge("A", "C"); g.addEdge("B", "D"); g.addEdge("C", "E"); g.addEdge("D", "E"); g.addEdge("D", "F"); g.addEdge("E", "F"); console.log(g.depthFirstTraversalRecursive("A")); // ["A", "B", "D", "E", "F", "C"]

Iterative DFT Implementation

The iterative approach uses an explicit stack to keep track of vertices to visit:

// Iterative DFT implementation class Graph { // ... previous methods ... depthFirstTraversalIterative(startVertex) { const stack = [startVertex]; const result = []; const visited = {}; visited[startVertex] = true; while (stack.length) { const currentVertex = stack.pop(); result.push(currentVertex); this.adjacencyList[currentVertex].forEach(neighbor => { if (!visited[neighbor]) { visited[neighbor] = true; stack.push(neighbor); } }); } return result; } } // Example usage console.log(g.depthFirstTraversalIterative("A")); // May produce different order than recursive version

Time Complexity: O(V + E) where V is the number of vertices and E is the number of edges

Space Complexity: O(V) for the visited set and stack/recursion call stack

Applications of DFT

DFT vs. BFT Comparison

Aspect Depth-First Traversal Breadth-First Traversal
Data Structure Stack (explicit or call stack) Queue
Traversal Pattern Deep exploration before backtracking Level by level exploration
Best For Path finding, maze solving, topological sort Shortest path, social networks, level-order tasks
Memory Usage Lower for deep graphs Lower for wide graphs
Implementation Simpler recursive solution Usually implemented iteratively

Practice with LeetCode Problems

Note: Previously, this course referenced the CodeSignal Arcade for practice, which is no longer available. The LeetCode problems below follow the same principles and are an excellent alternative for practicing graph traversal.