Graph Basics and Theory


1. Basics of Graphs


1.1 What is a Graph?

A graph is a non-linear data structure consisting of:

Formally, a graph G is defined as:

G = (V, E)
Where:

Graphs are used to model relationships or connections between objects (like social networks, maps, and recommendation systems).


1.2 Types of Graphs


1.2.1 Directed vs Undirected Graph

1.2.2 Weighted vs Unweighted Graph

1.2.3 Cyclic vs Acyclic Graph

1.2.4 Connected vs Disconnected Graph

1.2.5 Special Graphs


1.3 Degree of a Vertex

Example:

0 → 1 → 2
↑       |
└-------┘

1.4 Connected Components


1.5 Graph Representation


1.5.1 Adjacency Matrix

int[][] adj = new int[V][V];
adj[u][v] = 1; // Edge from u to v
adj[v][u] = 1; // If undirected

1.5.2 Adjacency List (ArrayList of Lists)

List<List<Integer>> adj = new ArrayList<>();
for (int i = 0; i < V; i++) adj.add(new ArrayList<>());
adj.get(u).add(v); // Directed
adj.get(v).add(u); // If undirected

1.5.3 Adjacency List (Map-Based)

Map<Integer, List<Integer>> graph = new HashMap<>();
graph.putIfAbsent(u, new ArrayList<>());
graph.get(u).add(v);

1.5.4 Weighted Graph (List of Pairs)

class Pair {
    int node, weight;
    Pair(int n, int w) { node = n; weight = w; }
}
List<List<Pair>> adj = new ArrayList<>();

1.5.5 Edge List

List<int[]> edges = new ArrayList<>();
edges.add(new int[]{u, v});
edges.add(new int[]{u, v, weight}); // weighted

Representation Comparison

Representation Space Edge Check Best For
Adjacency Matrix O(V²) O(1) Dense graphs
Adjacency List O(V + E) O(deg) Sparse graphs, BFS/DFS
Map-based List O(V + E) O(1 avg) Dynamic/labelled graphs
Edge List O(E) O(E) Sorting edges (Kruskal)

2. Graph Traversals


2.1 Breadth-First Search (BFS)


Intuition:


Java Code:

public void bfs(int start, List<List<Integer>> adj, boolean[] visited) {
    Queue<Integer> queue = new LinkedList<>();
    queue.offer(start);
    visited[start] = true;

    while (!queue.isEmpty()) {
        int node = queue.poll();
        System.out.print(node + " ");

        for (int neighbor : adj.get(node)) {
            if (!visited[neighbor]) {
                visited[neighbor] = true;
                queue.offer(neighbor);
            }
        }
    }
}

Dry Run:

Graph:

0: [1, 3]
1: [2]
3: [4]
4: [5]
5: [2]

Start = 0
Queue: [0]
Visited: [T, F, F, F, F, F]

Traversal:

0 → queue: [1,3]
1 → queue: [3,2]
3 → queue: [2,4]
2 → queue: [4]
4 → queue: [5]
5 → queue: []

Output: 0 1 3 2 4 5


Time & Space:


2.2 Depth-First Search (DFS)


Intuition:


Java Code (Recursive):

public void dfs(int node, List<List<Integer>> adj, boolean[] visited) {
    visited[node] = true;
    System.out.print(node + " ");

    for (int neighbor : adj.get(node)) {
        if (!visited[neighbor]) {
            dfs(neighbor, adj, visited);
        }
    }
}

Java Code (Iterative using Stack):

public void dfsIterative(int start, List<List<Integer>> adj, boolean[] visited) {
    Stack<Integer> stack = new Stack<>();
    stack.push(start);

    while (!stack.isEmpty()) {
        int node = stack.pop();

        if (!visited[node]) {
            visited[node] = true;
            System.out.print(node + " ");
        }

        for (int neighbor : adj.get(node)) {
            if (!visited[neighbor]) {
                stack.push(neighbor);
            }
        }
    }
}

Dry Run (Same graph):

Call: dfs(0)

dfs(0) → 0
dfs(1) → 1
dfs(2) → 2
dfs(3) → 3
dfs(4) → 4
dfs(5) → 5

Output: 0 1 2 3 4 5


Time & Space:


Summary

Algorithm Used For Data Structure Time
BFS Shortest path (unweighted), Level Order Queue O(V + E)
DFS Pathfinding, Topological Sort, SCC Recursion/Stack O(V + E)