Skip to main content
Graph Algorithms

Overview

Graph algorithms solve problems involving nodes and edges. Master these core algorithms to tackle most graph problems.

When to Use

Shortest Path

Dijkstra, Bellman-Ford, Floyd-Warshall

MST

Kruskal, Prim for minimum spanning tree

Topological Sort

Task ordering, course prerequisites

Cycle Detection

DFS colors or Union Find

Key Algorithms

1. Dijkstra’s Algorithm

import heapq
from collections import defaultdict

def dijkstra(graph, start):
    """Shortest paths from start to all nodes - O((V+E) log V)"""
    distances = {node: float('inf') for node in graph}
    distances[start] = 0
    pq = [(0, start)]
    
    while pq:
        dist, node = heapq.heappop(pq)
        
        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(pq, (new_dist, neighbor))
    
    return distances

2. Bellman-Ford

def bellman_ford(n, edges, start):
    """Handles negative weights, detects negative cycles - O(VE)"""
    distances = [float('inf')] * n
    distances[start] = 0
    
    # Relax all edges V-1 times
    for _ in range(n - 1):
        for u, v, w in edges:
            if distances[u] + w < distances[v]:
                distances[v] = distances[u] + w
    
    # Check for negative cycle
    for u, v, w in edges:
        if distances[u] + w < distances[v]:
            return None  # Negative cycle exists
    
    return distances

3. Topological Sort (Kahn’s BFS)

from collections import deque, defaultdict

def topological_sort(n, prerequisites):
    """Return valid ordering or empty if cycle exists"""
    graph = defaultdict(list)
    in_degree = [0] * n
    
    for course, prereq in prerequisites:
        graph[prereq].append(course)
        in_degree[course] += 1
    
    queue = deque([i for i in range(n) if in_degree[i] == 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) == n else []

4. Kruskal’s MST

class UnionFind:
    def __init__(self, n):
        self.parent = list(range(n))
        self.rank = [0] * n
    
    def find(self, x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]
    
    def union(self, x, y):
        px, py = self.find(x), self.find(y)
        if px == py:
            return False
        if self.rank[px] < self.rank[py]:
            px, py = py, px
        self.parent[py] = px
        if self.rank[px] == self.rank[py]:
            self.rank[px] += 1
        return True

def kruskal(n, edges):
    """Find minimum spanning tree - O(E log E)"""
    # Sort edges by weight
    edges.sort(key=lambda x: x[2])
    
    uf = UnionFind(n)
    mst = []
    total_weight = 0
    
    for u, v, weight in edges:
        if uf.union(u, v):
            mst.append((u, v, weight))
            total_weight += weight
            if len(mst) == n - 1:
                break
    
    return mst, total_weight

Complexity Comparison

AlgorithmTimeSpaceUse Case
DijkstraO((V+E) log V)O(V)Non-negative weights
Bellman-FordO(VE)O(V)Negative weights
Floyd-WarshallO(V^3)O(V^2)All pairs shortest
KruskalO(E log E)O(V)Sparse graphs MST
PrimO(E log V)O(V)Dense graphs MST

Practice Problems