Back to Main ACS 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 (Java) class Graph { private Map<String, List<String>> adjacencyList = new HashMap<>(); public void addVertex(String vertex) { adjacencyList.putIfAbsent(vertex, new ArrayList<>()); } public void addEdge(String vertex1, String vertex2) { adjacencyList.get(vertex1).add(vertex2); // For undirected graph, add the reverse edge too // adjacencyList.get(vertex2).add(vertex1); } }

Recursive DFT Implementation

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

// Recursive DFT implementation (Java) class Graph { private Map<String, List<String>> adjacencyList = new HashMap<>(); // ... addVertex and addEdge methods ... public List<String> depthFirstTraversalRecursive(String startVertex) { List<String> result = new ArrayList<>(); Set<String> visited = new HashSet<>(); dfs(startVertex, visited, result); return result; } private void dfs(String vertex, Set<String> visited, List<String> result) { if (vertex == null || visited.contains(vertex)) return; visited.add(vertex); result.add(vertex); for (String neighbor : adjacencyList.getOrDefault(vertex, new ArrayList<>())) { if (!visited.contains(neighbor)) { dfs(neighbor, visited, result); } } } } // Example usage Graph 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"); System.out.println(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 (Java) class Graph { private Map<String, List<String>> adjacencyList = new HashMap<>(); // ... addVertex and addEdge methods ... public List<String> depthFirstTraversalIterative(String startVertex) { List<String> result = new ArrayList<>(); Set<String> visited = new HashSet<>(); Deque<String> stack = new ArrayDeque<>(); stack.push(startVertex); while (!stack.isEmpty()) { String current = stack.pop(); if (!visited.contains(current)) { visited.add(current); result.add(current); for (String neighbor : adjacencyList.getOrDefault(current, new ArrayList<>())) { if (!visited.contains(neighbor)) { stack.push(neighbor); } } } } return result; } } // Example usage // System.out.println(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.