Depth First Search (DFS) is a graph traversal algorithm that explores all adjacent vertices of a node one by one, diving deep into each vertex's reachable nodes before backtracking. Unlike trees, graphs may have cycles, so a visited array is used to prevent revisiting nodes. This ensures all nodes are processed efficiently without repetition.
# dfs_on_graph.pydef dfs(adjlist, visited, node): """ Performs DFS traversal on a graph using adjacency list """ visited[node] = True print(node, end=" ") # Visit all unvisited neighbors recursively for neighbor in adjlist[node]: if not visited[neighbor]: dfs(adjlist, visited, neighbor)def dfs_complete_graph(adjlist): """ Performs DFS on all components of the graph """ visited = [False] * len(adjlist) result = [] for i in range(len(adjlist)): if not visited[i]: component_start = len([x for x in visited if x]) # Count visited nodes dfs(adjlist, visited, i) print() # New line after each component# Example usageif __name__ == "__main__": # Adjacency list representation adjlist = [ [1, 3, 2], # Node 0 connected to 1, 3, 2 [0], # Node 1 connected to 0 [0, 3], # Node 2 connected to 0, 3 [0, 2, 4, 5], # Node 3 connected to 0, 2, 4, 5 [3], # Node 4 connected to 3 [3] # Node 5 connected to 3 ] print("DFS Traversal of the graph:") dfs_complete_graph(adjlist)# Alternative: DFS from a specific starting nodedef dfs_from_node(adjlist, start): visited = [False] * len(adjlist) print(f"DFS starting from node {start}:") dfs(adjlist, visited, start) print()# Example: Start DFS from node 0# dfs_from_node(adjlist, 0)# Output: 0 1 3 2 4 5
// dfs_on_graph.jsfunction dfs(adjList, visited, node) { /** * Performs DFS traversal on a graph using adjacency list */ visited[node] = true; process.stdout.write(node + " "); // Visit all unvisited neighbors recursively for (const neighbor of adjList[node]) { if (!visited[neighbor]) { dfs(adjList, visited, neighbor); } }}function dfsCompleteGraph(adjList) { /** * Performs DFS on all components of the graph */ const visited = new Array(adjList.length).fill(false); for (let i = 0; i < adjList.length; i++) { if (!visited[i]) { dfs(adjList, visited, i); console.log(); // New line after each component } }}// Example usagefunction main() { // Adjacency list representation const adjList = [ [1, 3, 2], // Node 0 connected to 1, 3, 2 [0], // Node 1 connected to 0 [0, 3], // Node 2 connected to 0, 3 [0, 2, 4, 5], // Node 3 connected to 0, 2, 4, 5 [3], // Node 4 connected to 3 [3] // Node 5 connected to 3 ]; console.log("DFS Traversal of the graph:"); dfsCompleteGraph(adjList);}// Alternative: DFS from a specific starting nodefunction dfsFromNode(adjList, start) { const visited = new Array(adjList.length).fill(false); console.log(`DFS starting from node ${start}:`); dfs(adjList, visited, start); console.log();}main();// Example: Start DFS from node 0// dfsFromNode(adjList, 0);// Output: 0 1 3 2 4 5
The DFS quickly finds the target node, so the traversal terminates early, without visiting all vertices and edges.
In the best-case scenario, we visit a small subset of nodes and edges, leading to a faster termination. However, in general, DFS's worst-case complexity is still O(V + E) because it would potentially explore all nodes and edges.
On average, DFS explores all vertices and edges in the graph. This happens when the graph is not sparse or highly structured (i.e., it's not too easy to find the target node early).
The average case for DFS still leads to visiting all nodes and edges, so it remains O(V+E).