A graph is a collection of nodes connected by edges, used to model relationships and networks in computer science. This post introduces graph representations, key concepts, and provides practical Python examples and problems for understanding graphs and their applications.
Graph / Adjacency List
Overview
A graph is a set of nodes (vertices) connected by edges.
- Can be directed or undirected
- Can be weighted or unweighted
Graphs are commonly represented using:
- Adjacency list (efficient for sparse graphs)
- Adjacency matrix (efficient for dense graphs)
🧩 Visualizing a Graph
Suppose we have the following graph:
graph = {
'A': ['B', 'C'],
'B': ['D'],
'C': ['E'],
'D': [],
'E': ['D']
}
Diagram
graph TD;
A --> B;
A --> C;
B --> D;
C --> E;
E --> D;
- Nodes: A, B, C, D, E
- Edges: (A,B), (A,C), (B,D), (C,E), (E,D)
🛠️ How to Use (Python)
# Example of a directed, unweighted graph using an adjacency list (dictionary)
graph = {
'A': ['B', 'C'], # Node A points to B and C
'B': ['D'], # Node B points to D
'C': ['E'], # Node C points to E
'D': [], # Node D has no outgoing edges
'E': ['D'] # Node E points to D
}
# Access neighbors: graph['A'] returns ['B', 'C']
# All operations above are O(1) for lookup, O(k) for iterating neighbors
# Example:
print(graph['A']) # Output: ['B', 'C']
🧩 Cycle Detection Flow
Suppose we run cycle detection on the above graph. The DFS stack and visited set change as follows:
Step | Node | rec_stack | visited | Cycle Detected? |
---|---|---|---|---|
1 | A | {A} | {A} | No |
2 | B | {A, B} | {A, B} | No |
3 | D | {A, B, D} | {A, B, D} | No |
4 | B | {A} | {A, B, D} | No |
5 | C | {A, C} | {A, B, C, D} | No |
6 | E | {A, C, E} | {A, B, C, D, E} | No |
7 | D | {A, C, E, D} | {A, B, C, D, E} | No |
8 | E | {A, C} | {A, B, C, D, E} | No |
9 | C | {A} | {A, B, C, D, E} | No |
10 | A | {} | {A, B, C, D, E} | No |
- No cycle is detected in this example.
📘 Sample Problem 1: Detect Cycle in Directed Graph
Return True if the graph has a cycle.
def has_cycle(graph):
visited = set()
rec_stack = set()
def dfs(node):
# If node is in recursion stack, a cycle is found
if node in rec_stack:
return True
# If already visited, skip
if node in visited:
return False
visited.add(node)
rec_stack.add(node)
for neighbor in graph[node]:
if dfs(neighbor):
return True
rec_stack.remove(node)
return False
for node in graph:
if dfs(node):
return True
return False
# Example:
graph = {
'A': ['B', 'C'],
'B': ['D'],
'C': ['E'],
'D': [],
'E': ['D']
}
print(has_cycle(graph)) # Output: False
🔁 Variants
- Weighted graphs (store edge weights as tuples or dict)
- Bidirectional graphs (undirected)
- Grid graphs (2D neighbors)
- Disjoint-set (union-find structure)
Comments
Add a Comment
Please be mindful
There are currently no comments on this article, be the first to add one below