-
Notifications
You must be signed in to change notification settings - Fork 0
/
graph_traversal_dfs.py
71 lines (52 loc) · 2.44 KB
/
graph_traversal_dfs.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# Implementation of DFS and BFS traversal on a graph (adjacency list representation)
# In the recursive DFS implementation, at each level of recursion,
# the current node is treated as the "start" node. The function
# explores all unvisited neighbors of this node, and for each neighbor,
# it recursively calls itself, treating that neighbor as the new "start" node.
# This process continues until all reachable nodes have been visited.
# Time complexity: O(V + E), where V is the number of vertices and E is the number of edges
# Space complexity: O(V), where V is the number of vertices
# The space complexity is O(V) because the visited set can contain at most V vertices.
# The recursive calls also consume space on the call stack, but the maximum depth of the call stack is O(V) as well.
def dfs_recursive(graph, start, visited=None):
# Assume we start with an empty set of visited nodes
if visited is None:
visited = set()
visited.add(start)
print(f"Visiting Node {start}")
for neighbor in graph.get(start, []):
if neighbor not in visited:
print(f"Visiting Node {neighbor} from {start} since it is not visited \n")
# Recursively visit the neighbor if it has not been visited
dfs_recursive(graph, neighbor, visited)
# Not often used in practice, but it's good to know how to implement it
# DFS inherently follows a recursive pattern
def dfs_iterative(graph, start):
visited = set()
stack = [start] # Using a list as a stack
while stack:
node = stack.pop()
if node not in visited:
visited.add(node)
print(node) # Process the node
# Add neighbors to the stack
# Not a must to use reversed() here,
# but it's a good practice to maintain the order of neighbors
for neighbor in reversed(graph.get(node, [])):
if neighbor not in visited:
stack.append(neighbor)
# For a disconnected graph, we need to ensure that all nodes are visited
def dfs_full(graph):
visited = set()
for node in graph:
if node not in visited:
dfs_recursive(graph, node, visited)
# Example usage
if __name__ == "__main__":
graph = {1: [2, 3], 2: [4], 3: [], 4: [5], 5: []}
print("DFS Recursive Traversal: \n")
dfs_recursive(graph, 2)
print("\nDFS Iterative Traversal: \n")
dfs_iterative(graph, 2)
print("\nDFS Full Traversal: \n")
dfs_full(graph)