Graphs
A graph is a non-linear data structure consisting of nodes (vertices) and edges that connect them. Graphs are fundamental in computer science, modeling relationships in social networks, transportation systems, computer networks, and countless other applications.
Interactive Graph Visualization
Explore graph traversal algorithms with our interactive visualizer. Create custom graphs, drag nodes around, and watch BFS and DFS algorithms traverse the graph step-by-step with color-coded animations.
Graph Operations & Traversal Algorithms
Add Node
Create a new vertex
Add Edge
Connect two vertices
Graph Traversal
Animate traversal algorithms
Interactive Graph Visualization
Drag nodes to reposition • Click to deselect • 4 nodes, 3 edges
Graph Traversal Algorithms
Explores all neighbors at the current depth before moving to nodes at the next depth level. Uses a queue data structure and guarantees the shortest path in unweighted graphs.
Time: O(V + E), Space: O(V)
Explores as far as possible along each branch before backtracking. Uses recursion (or stack) and is useful for detecting cycles and finding connected components.
Time: O(V + E), Space: O(V)
Graph Fundamentals
Core Components
- • Vertices (Nodes): Individual entities in the graph
- • Edges (Links): Connections between vertices
- • Degree: Number of edges connected to a vertex
- • Path: Sequence of vertices connected by edges
- • Cycle: Path that starts and ends at the same vertex
Graph Properties
- • Connected: Path exists between any two vertices
- • Sparse vs Dense: Few edges vs many edges
- • Planar: Can be drawn without edge crossings
- • Bipartite: Vertices can be divided into two disjoint sets
- • Complete: Every vertex connected to every other vertex
Types of Graphs
Directed vs Undirected
Directed: Edges have direction (A → B)
Undirected: Edges are bidirectional (A ↔ B)
Weighted vs Unweighted
Weighted: Edges have associated costs/distances
Unweighted: All edges have equal value
Cyclic vs Acyclic
Cyclic: Contains at least one cycle
Acyclic: No cycles (e.g., trees, DAGs)
Connected vs Disconnected
Connected: Path exists between all vertices
Disconnected: Some vertices are unreachable
Graph Representation Methods
Adjacency Matrix
2D array where matrix[i][j] represents edge from vertex i to vertex j
A B C
A [0 1 1]
B [1 0 1]
C [1 1 0]
- • Space: O(V²) - always uses V² space
- • Edge Check: O(1) - direct array access
- • Add Edge: O(1) - set matrix value
- • Get Neighbors: O(V) - scan entire row
- • Best for: Dense graphs, frequent edge queries
Adjacency List ⭐
Array/Map of lists where each vertex stores its neighbors
A: [B, C]
B: [A, C]
C: [A, B]
- • Space: O(V + E) - only stores existing edges
- • Edge Check: O(degree) - search neighbor list
- • Add Edge: O(1) - append to list
- • Get Neighbors: O(degree) - return list
- • Best for: Sparse graphs, traversal algorithms
💡 Recommendation: Adjacency List is often more efficient for sparse graphs (few edges relative to vertices), which describes most real-world graphs. It's the preferred choice for traversal algorithms like BFS and DFS.
Graph Traversal Algorithms
Breadth-First Search (BFS)
Algorithm:
- Start with a queue containing the start vertex
- Mark the start vertex as visited
- While queue is not empty:
- • Dequeue a vertex and process it
- • Add all unvisited neighbors to queue
- • Mark neighbors as visited
Time Complexity: O(V + E)
Space Complexity: O(V) for queue and visited set
Properties: Explores level by level, finds shortest path in unweighted graphs
Applications: Shortest path, social networks, web crawling
Depth-First Search (DFS)
Algorithm:
- Start with a stack containing the start vertex
- While stack is not empty:
- • Pop a vertex from stack
- • If not visited, mark as visited and process
- • Add all unvisited neighbors to stack
- Alternative: Use recursion (implicit stack)
Time Complexity: O(V + E)
Space Complexity: O(V) for stack and visited set
Properties: Explores as deep as possible before backtracking
Applications: Cycle detection, topological sorting, maze solving
Operation Complexity Analysis
| Operation | Adjacency Matrix | Adjacency List | Notes |
|---|---|---|---|
| Space | O(V²) | O(V + E) | List is better for sparse graphs |
| Add Vertex | O(V²) | O(1) | Matrix needs resizing |
| Add Edge | O(1) | O(1) | Both constant time |
| Check Edge | O(1) | O(degree) | Matrix has direct access |
| Get Neighbors | O(V) | O(degree) | List stores only actual neighbors |
| BFS/DFS | O(V²) | O(V + E) | List avoids checking non-edges |
Graph Implementation & Traversal Algorithms
Complete graph implementations using adjacency lists with both BFS and DFS traversal algorithms. Study how the queue in BFS enables level-order traversal while the stack in DFS enables deep exploration.
from collections import defaultdict, deque
class Graph:
"""
Graph implementation using Adjacency List representation
Supports both directed and undirected graphs
"""
def __init__(self, directed=False):
self.graph = defaultdict(list) # Adjacency list
self.directed = directed
self.vertices = set()
def add_vertex(self, vertex):
"""Add a vertex to the graph"""
self.vertices.add(vertex)
if vertex not in self.graph:
self.graph[vertex] = []
def add_edge(self, u, v, weight=1):
"""
Add an edge between vertices u and v
For undirected graphs, add edge in both directions
"""
self.vertices.add(u)
self.vertices.add(v)
# Add edge from u to v
self.graph[u].append((v, weight))
# For undirected graphs, add reverse edge
if not self.directed:
self.graph[v].append((u, weight))
def get_neighbors(self, vertex):
"""Get all neighbors of a vertex"""
return [neighbor for neighbor, weight in self.graph[vertex]]
def print_graph(self):
"""Print the adjacency list representation"""
for vertex in self.vertices:
neighbors = self.get_neighbors(vertex)
print(f"{vertex}: {neighbors}")
def bfs(self, start_vertex):
"""
Breadth-First Search traversal
Time Complexity: O(V + E)
Space Complexity: O(V)
"""
if start_vertex not in self.vertices:
return []
visited = set()
queue = deque([start_vertex])
traversal_order = []
visited.add(start_vertex)
while queue:
# Dequeue a vertex from front of queue
current = queue.popleft()
traversal_order.append(current)
# Visit all unvisited neighbors
for neighbor in self.get_neighbors(current):
if neighbor not in visited:
visited.add(neighbor)
queue.append(neighbor)
return traversal_order
def dfs(self, start_vertex):
"""
Depth-First Search traversal (iterative)
Time Complexity: O(V + E)
Space Complexity: O(V)
"""
if start_vertex not in self.vertices:
return []
visited = set()
stack = [start_vertex]
traversal_order = []
while stack:
# Pop a vertex from top of stack
current = stack.pop()
if current not in visited:
visited.add(current)
traversal_order.append(current)
# Add all unvisited neighbors to stack
# Add in reverse order to maintain left-to-right traversal
neighbors = self.get_neighbors(current)
for neighbor in reversed(neighbors):
if neighbor not in visited:
stack.append(neighbor)
return traversal_order
def dfs_recursive(self, start_vertex, visited=None):
"""
Depth-First Search traversal (recursive)
Time Complexity: O(V + E)
Space Complexity: O(V) - due to recursion stack
"""
if visited is None:
visited = set()
if start_vertex not in self.vertices:
return []
visited.add(start_vertex)
traversal_order = [start_vertex]
# Visit all unvisited neighbors recursively
for neighbor in self.get_neighbors(start_vertex):
if neighbor not in visited:
traversal_order.extend(
self.dfs_recursive(neighbor, visited)
)
return traversal_order
# Example usage and testing
if __name__ == "__main__":
# Create an undirected graph
g = Graph(directed=False)
# Add vertices and edges
g.add_edge('A', 'B')
g.add_edge('A', 'C')
g.add_edge('B', 'D')
g.add_edge('C', 'E')
g.add_edge('D', 'E')
g.add_edge('E', 'F')
print("Graph representation:")
g.print_graph()
print(f"\nBFS from A: {g.bfs('A')}")
print(f"DFS from A: {g.dfs('A')}")
print(f"DFS Recursive from A: {g.dfs_recursive('A')}") Real-World Applications
Social Networks
Model friendships, connections, and information spread. BFS finds shortest social distance.
Transportation
GPS navigation, flight routes, public transit. Weighted graphs represent distances or travel time.
Computer Networks
Internet topology, routing protocols, network analysis. DFS detects network loops.
Web Crawling
Search engines use BFS to discover web pages level by level from seed URLs.
Game Development
Pathfinding in games, decision trees, state machines. A* algorithm extends BFS.
Dependency Resolution
Package managers, build systems, task scheduling. DFS enables topological sorting.
Advanced Graph Algorithms
• Dijkstra's Algorithm: Shortest path in weighted graphs
• Minimum Spanning Tree: Kruskal's and Prim's algorithms
• Topological Sort: Ordering vertices in directed acyclic graphs
• Strongly Connected Components: Finding cycles in directed graphs
• Maximum Flow: Ford-Fulkerson algorithm for network flow problems