Graphs & Graph Algorithms

Graph Basics

A graph is a data structure consisting of vertices (nodes) connected by edges. Graphs can be directed or undirected, weighted or unweighted.

Graph Representation

// Adjacency List representation
class Graph {
    private Map<Integer, List<Integer>> adjacencyList;
    
    public Graph() {
        adjacencyList = new HashMap<>();
    }
    
    public void addVertex(int vertex) {
        adjacencyList.putIfAbsent(vertex, new ArrayList<>());
    }
    
    public void addEdge(int source, int destination) {
        adjacencyList.get(source).add(destination);
        // For undirected graph, also add reverse edge
        // adjacencyList.get(destination).add(source);
    }
    
    public List<Integer> getNeighbors(int vertex) {
        return adjacencyList.getOrDefault(vertex, new ArrayList<>());
    }
}

// Adjacency Matrix representation
class GraphMatrix {
    private int[][] adjacencyMatrix;
    private int numVertices;
    
    public GraphMatrix(int numVertices) {
        this.numVertices = numVertices;
        this.adjacencyMatrix = new int[numVertices][numVertices];
    }
    
    public void addEdge(int source, int destination) {
        adjacencyMatrix[source][destination] = 1;
        // For undirected graph
        // adjacencyMatrix[destination][source] = 1;
    }
}

Graph Traversal

  • Depth-First Search (DFS): Explore as far as possible along each branch before backtracking
  • Breadth-First Search (BFS): Explore all neighbors at the present depth before moving to next level

DFS Implementation

// DFS using recursion
void dfsRecursive(int vertex, boolean[] visited, List<Integer> result) {
    visited[vertex] = true;
    result.add(vertex);
    
    for (int neighbor : getNeighbors(vertex)) {
        if (!visited[neighbor]) {
            dfsRecursive(neighbor, visited, result);
        }
    }
}

// DFS using stack (iterative)
List<Integer> dfsIterative(int startVertex) {
    List<Integer> result = new ArrayList<>();
    boolean[] visited = new boolean[numVertices];
    Stack<Integer> stack = new Stack<>();
    
    stack.push(startVertex);
    
    while (!stack.isEmpty()) {
        int vertex = stack.pop();
        
        if (!visited[vertex]) {
            visited[vertex] = true;
            result.add(vertex);
            
            for (int neighbor : getNeighbors(vertex)) {
                if (!visited[neighbor]) {
                    stack.push(neighbor);
                }
            }
        }
    }
    
    return result;
}

BFS Implementation

List<Integer> bfs(int startVertex) {
    List<Integer> result = new ArrayList<>();
    boolean[] visited = new boolean[numVertices];
    Queue<Integer> queue = new LinkedList<>();
    
    queue.offer(startVertex);
    visited[startVertex] = true;
    
    while (!queue.isEmpty()) {
        int vertex = queue.poll();
        result.add(vertex);
        
        for (int neighbor : getNeighbors(vertex)) {
            if (!visited[neighbor]) {
                visited[neighbor] = true;
                queue.offer(neighbor);
            }
        }
    }
    
    return result;
}

Common Graph Problems

  • Connected Components: Find all connected components in a graph
  • Cycle Detection: Detect cycles in directed/undirected graphs
  • Topological Sort: Order vertices in directed acyclic graph
  • Shortest Path: Find shortest path between vertices
  • Minimum Spanning Tree: Find minimum weight spanning tree

Open full interactive app