Learning

Graphs & Graph Algorithms

Graphs & Graph Algorithms

Graph Representations

python
# Adjacency List (most common) graph = { 'A': ['B', 'C'], 'B': ['A', 'D'], 'C': ['A', 'D'], 'D': ['B', 'C', 'E'], 'E': ['D'] } # Adjacency Matrix nodes = ['A', 'B', 'C', 'D', 'E'] matrix = [[0]*5 for _ in range(5)] edges = [('A','B'), ('A','C'), ('B','D'), ('C','D'), ('D','E')] for u, v in edges: i, j = nodes.index(u), nodes.index(v) matrix[i][j] = matrix[j][i] = 1

BFS Traversal

python
from collections import deque def bfs(graph, start): visited = set() queue = deque([start]) visited.add(start) result = [] while queue: node = queue.popleft() result.append(node) for neighbor in graph[node]: if neighbor not in visited: visited.add(neighbor) queue.append(neighbor) return result print(bfs(graph, 'A')) # ['A', 'B', 'C', 'D', 'E']

DFS Traversal

python
def dfs(graph, start): visited = set() result = [] def _dfs(node): visited.add(node) result.append(node) for neighbor in graph[node]: if neighbor not in visited: _dfs(neighbor) _dfs(start) return result print(dfs(graph, 'A')) # ['A', 'B', 'D', 'C', 'E'] (order varies)

Shortest Path (BFS for unweighted)

python
def shortest_path(graph, start, end): queue = deque([(start, [start])]) visited = {start} while queue: node, path = queue.popleft() if node == end: return path for neighbor in graph[node]: if neighbor not in visited: visited.add(neighbor) queue.append((neighbor, path + [neighbor])) return None print(shortest_path(graph, 'A', 'E')) # ['A', 'B', 'D', 'E'] or ['A', 'C', 'D', 'E']

Dijkstra's Algorithm (weighted)

python
import heapq def dijkstra(graph, start): distances = {node: float('inf') for node in graph} distances[start] = 0 heap = [(0, start)] while heap: dist, node = heapq.heappop(heap) if dist > distances[node]: continue for neighbor, weight in graph[node]: new_dist = dist + weight if new_dist < distances[neighbor]: distances[neighbor] = new_dist heapq.heappush(heap, (new_dist, neighbor)) return distances # Weighted graph: {node: [(neighbor, weight), ...]} weighted = { 'A': [('B', 1), ('C', 4)], 'B': [('C', 2), ('D', 5)], 'C': [('D', 1)], 'D': [] } print(dijkstra(weighted, 'A')) # {'A': 0, 'B': 1, 'C': 3, 'D': 4}

Topological Sort

python
def topological_sort(graph): in_degree = {node: 0 for node in graph} for node in graph: for neighbor in graph[node]: in_degree[neighbor] += 1 queue = deque([n for n in in_degree if in_degree[n] == 0]) result = [] while queue: node = queue.popleft() result.append(node) for neighbor in graph[node]: in_degree[neighbor] -= 1 if in_degree[neighbor] == 0: queue.append(neighbor) return result if len(result) == len(graph) else None # DAG DAG = { 'A': ['B', 'C'], 'B': ['D'], 'C': ['D'], 'D': [] } print(topological_sort(DAG)) # ['A', 'B', 'C', 'D'] or ['A', 'C', 'B', 'D']

Cycle Detection (DFS)

python
def has_cycle(graph): visited = set() rec_stack = set() def _dfs(node): visited.add(node) rec_stack.add(node) for neighbor in graph[node]: if neighbor not in visited: if _dfs(neighbor): return True elif neighbor in rec_stack: return True rec_stack.remove(node) return False for node in graph: if node not in visited: if _dfs(node): return True return False
Key Rules
  • •Adjacency list: O(V+E) space, efficient for sparse graphs. Adjacency matrix: O(V²) space, efficient for dense graphs
  • •BFS uses queue, explores level-by-level — finds shortest path in unweighted graphs
  • •DFS uses stack/recursion, explores depth-first — useful for topological sort, cycle detection, path finding
  • •Dijkstra's: O((V+E) log V) with min-heap — works for non-negative weights only
  • •Topological sort only works on DAGs (Directed Acyclic Graphs) — uses Kahn's algorithm (BFS) or DFS
  • •Cycle detection in directed graphs: use recursion stack. In undirected graphs: check if neighbor is visited and not parent
Your Task

Implement: 1) `bfs(graph, start)` returning traversal list. 2) `dfs(graph, start)` returning traversal list. 3) `shortest_path(graph, start, end)` returning path list. 4) `dijkstra(graph, start)` returning distance dict (weighted graph with (neighbor, weight) tuples). 5) `topological_sort(graph)` for a DAG. 6) `has_cycle(graph)` for directed graphs. Create example graphs for each and demonstrate.

EditorPython · JSX
PreviewUpdates on Run Tests
Loading preview…
Tests
Should implement bfs with deque
Should implement dfs recursively
Should implement shortest_path returning path
Should implement dijkstra with heapq
Should implement topological_sort with in-degree
Should implement has_cycle with rec_stack