Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
Program to reverse the directed graph in Python
A directed graph reversal means changing the direction of all edges − if an edge goes from node u to v, it becomes an edge from v to u. Given an adjacency list representation, we need to create the reverse graph where all edge directions are flipped.
Problem Understanding
Consider a directed graph with nodes numbered from 0 to n-1. If the original graph has an edge from node i to node j, the reversed graph will have an edge from node j to node i.
Algorithm
The algorithm iterates through each node and its adjacent nodes, then adds reverse edges to the result ?
- Create an empty adjacency list for the reversed graph
- For each node i and its adjacency list, add i to the adjacency list of each neighbor
- Return the reversed adjacency list
Implementation
def reverse_graph(graph):
"""
Reverse a directed graph represented as adjacency list
Args: graph - list of lists representing adjacency list
Returns: reversed graph as adjacency list
"""
n = len(graph)
reversed_graph = [[] for _ in range(n)]
# For each node and its neighbors
for node in range(n):
for neighbor in graph[node]:
# Add reverse edge: neighbor -> node
reversed_graph[neighbor].append(node)
return reversed_graph
# Example usage
original_graph = [[1, 2], [4], [4], [1, 2], [3]]
result = reverse_graph(original_graph)
print("Original graph:", original_graph)
print("Reversed graph:", result)
Original graph: [[1, 2], [4], [4], [1, 2], [3]] Reversed graph: [[], [0, 3], [0, 3], [4], [1, 2]]
Step-by-Step Trace
Let's trace through the algorithm with the example graph ?
def reverse_graph_with_trace(graph):
n = len(graph)
reversed_graph = [[] for _ in range(n)]
print(f"Initial reversed graph: {reversed_graph}")
for node in range(n):
print(f"\nProcessing node {node} with neighbors {graph[node]}:")
for neighbor in graph[node]:
reversed_graph[neighbor].append(node)
print(f" Added edge {neighbor} -> {node}")
print(f" Current state: {reversed_graph}")
return reversed_graph
# Trace the example
graph = [[1, 2], [4], [4], [1, 2], [3]]
result = reverse_graph_with_trace(graph)
Initial reversed graph: [[], [], [], [], []] Processing node 0 with neighbors [1, 2]: Added edge 1 -> 0 Current state: [[], [0], [], [], []] Added edge 2 -> 0 Current state: [[], [0], [0], [], []] Processing node 1 with neighbors [4]: Added edge 4 -> 1 Current state: [[], [0], [0], [], [1]] Processing node 2 with neighbors [4]: Added edge 4 -> 2 Current state: [[], [0], [0], [], [1, 2]] Processing node 3 with neighbors [1, 2]: Added edge 1 -> 3 Current state: [[], [0, 3], [0], [], [1, 2]] Added edge 2 -> 3 Current state: [[], [0, 3], [0, 3], [], [1, 2]] Processing node 4 with neighbors [3]: Added edge 3 -> 4 Current state: [[], [0, 3], [0, 3], [4], [1, 2]]
Time and Space Complexity
| Aspect | Complexity | Explanation |
|---|---|---|
| Time Complexity | O(V + E) | Visit each vertex and edge once |
| Space Complexity | O(V + E) | Store reversed adjacency list |
Where V is the number of vertices and E is the number of edges in the graph.
Conclusion
Reversing a directed graph involves creating a new adjacency list where each edge direction is flipped. The algorithm efficiently processes each edge once, making it optimal for this operation with O(V + E) time complexity.
