Loading...
Development

With C Code, Diagrams, Algorithms, and Examples

Complete Notes on Graphs

With C Code, Diagrams, Algorithms, and Examples


1. Graph Terminology

TermDefinition
GraphCollection of vertices (V) and edges (E)
Vertex/NodeEntity
EdgeConnection between vertices
Directed Graph (Digraph)Edges have direction
Undirected GraphEdges are bidirectional
Weighted GraphEdges have weights/costs
DegreeNumber of edges connected to a vertex
In-degree / Out-degreeFor directed graphs
PathSequence of vertices connected by edges
CyclePath that starts and ends at same vertex
Connected GraphPath exists between every pair of vertices
Connected ComponentMaximal connected subgraph
TreeConnected acyclic graph
Spanning TreeSubgraph that is a tree and includes all vertices

2. Graph Representations

A. Adjacency Matrix

2D array adj[V][V]
adj[i][j] = 1 if edge i→j, else 0 (unweighted)
adj[i][j] = weight for weighted

int adj[MAX][MAX];

Pros & Cons

ProsCons
O(1) edge checkO(V²) space
Fast edge additionNot good for sparse graphs

B. Adjacency List

Array of linked lists
head[i] → list of neighbors of vertex i

typedef struct Node {
    int vertex;
    int weight;  // for weighted
    struct Node* next;
} Node;

Node* head[MAX];

Pros & Cons

ProsCons
O(V + E) spaceO(degree) edge check
Best for sparse graphsSlower edge lookup

C. Edge List (for Kruskal)

typedef struct {
    int u, v, w;
} Edge;
Edge edges[MAX_EDGES];

3. Graph Traversal

A. Depth-First Search (DFS)

Explore as far as possible along each branch.

Recursive DFS

void DFS(int u) {
    visited[u] = 1;
    printf("%d ", u);
    for (Node* v = head[u]; v != NULL; v = v->next) {
        if (!visited[v->vertex])
            DFS(v->vertex);
    }
}

Applications

  • Cycle detection
  • Topological sort
  • Strongly connected components
  • Path finding

B. Breadth-First Search (BFS)

Explore level by level using queue.

void BFS(int start) {
    Queue q;
    init(&q);
    visited[start] = 1;
    enqueue(&q, start);

    while (!isEmpty(&q)) {
        int u = dequeue(&q);
        printf("%d ", u);
        for (Node* v = head[u]; v != NULL; v = v->next) {
            if (!visited[v->vertex]) {
                visited[v->vertex] = 1;
                enqueue(&q, v->vertex);
            }
        }
    }
}

Applications

  • Shortest path (unweighted)
  • Level order
  • Bipartite check

4. Connected Components

void findComponents() {
    int component = 0;
    memset(visited, 0, sizeof(visited));
    for (int i = 0; i < V; i++) {
        if (!visited[i]) {
            component++;
            printf("Component %d: ", component);
            DFS(i);  // or BFS
            printf("\n");
        }
    }
}

5. Spanning Tree

A subgraph that is a tree and connects all vertices.

  • Number of edges = V - 1
  • No cycles

6. Minimum Cost Spanning Tree (MST)

Spanning tree with minimum total edge weight


A. Prim’s Algorithm (Greedy)

Grow MST from a starting vertex
Always pick minimum weight edge connecting a visited to unvisited vertex

Uses Priority Queue (Min-Heap)

void primMST() {
    int parent[V], key[V];
    bool inMST[V];
    PriorityQueue pq;

    for (int i = 0; i < V; i++) {
        key[i] = INF;
        inMST[i] = false;
    }

    key[0] = 0;
    insert(&pq, 0, 0);
    parent[0] = -1;

    while (!isEmpty(&pq)) {
        int u = extractMin(&pq);
        inMST[u] = true;

        for (Node* v = head[u]; v != NULL; v = v->next) {
            int vertex = v->vertex;
            int weight = v->weight;
            if (!inMST[vertex] && weight < key[vertex]) {
                key[vertex] = weight;
                parent[vertex] = u;
                insert(&pq, vertex, weight);
            }
        }
    }

    // Print MST
    for (int i = 1; i < V; i++)
        printf("%d - %d : %d\n", parent[i], i, key[i]);
}

Time: O((V + E) log V)


B. Kruskal’s Algorithm (Greedy + Union-Find)

Sort all edges → Pick smallest edge that doesn’t form cycle

int parent[MAX];

int find(int x) {
    if (parent[x] == x) return x;
    return parent[x] = find(parent[x]);
}

void unionSets(int x, int y) {
    parent[find(x)] = find(y);
}

void kruskalMST(Edge edges[], int E) {
    Edge result[V-1];
    int e = 0, i = 0;

    // Sort edges by weight
    qsort(edges, E, sizeof(Edge), cmp);

    for (int i = 0; i < V; i++) parent[i] = i;

    while (e < V-1 && i < E) {
        Edge next = edges[i++];
        int x = find(next.u);
        int y = find(next.v);
        if (x != y) {
            result[e++] = next;
            unionSets(x, y);
        }
    }

    // Print result
    for (int i = 0; i < e; i++)
        printf("%d - %d : %d\n", result[i].u, result[i].v, result[i].w);
}

Time: O(E log E)


7. Transitive Closure – Warshall’s Algorithm

Find reachability between all pairs
reach[i][j] = 1 if path exists from i to j

void warshall(int reach[V][V]) {
    // Initialize
    for (int i = 0; i < V; i++)
        for (int j = 0; j < V; j++)
            reach[i][j] = adj[i][j];

    // Add vertices as intermediates
    for (int k = 0; k < V; k++)
        for (int i = 0; i < V; i++)
            for (int j = 0; j < V; j++)
                reach[i][j] = reach[i][j] || (reach[i][k] && reach[k][j]);
}

Time: O(V³)
Use: Reachability, dependency graphs


8. Shortest Path

A. Dijkstra’s Algorithm

Single source, non-negative weights

void dijkstra(int src) {
    int dist[V];
    bool visited[V];
    PriorityQueue pq;

    for (int i = 0; i < V; i++) {
        dist[i] = INF;
        visited[i] = false;
    }
    dist[src] = 0;
    insert(&pq, src, 0);

    while (!isEmpty(&pq)) {
        int u = extractMin(&pq);
        if (visited[u]) continue;
        visited[u] = true;

        for (Node* v = head[u]; v != NULL; v = v->next) {
            int vertex = v->vertex;
            int weight = v->weight;
            if (!visited[vertex] && dist[u] + weight < dist[vertex]) {
                dist[vertex] = dist[u] + weight;
                insert(&pq, vertex, dist[vertex]);
            }
        }
    }

    // Print distances
    for (int i = 0; i < V; i++)
        printf("Distance to %d: %d\n", i, dist[i]);
}

Time: O((V + E) log V)


9. Comparison Table

AlgorithmUseTimeData Structure
DFSPath, cycleO(V+E)Stack
BFSShortest pathO(V+E)Queue
PrimMSTO((V+E)logV)Priority Queue
KruskalMSTO(E log E)Union-Find
WarshallAll-pairs reachabilityO(V³)Matrix
DijkstraSingle-source shortestO((V+E)logV)Priority Queue

10. Example Graph

    0 --1--> 1
    |       / \
    4      2   3
    |     /     \
    2 --8--> 3   7
  • Adjacency List:
    • 0: 1(1), 2(4)
    • 1: 2(2), 3(3)
    • 2: 3(8)
    • 3:

11. Practice Problems

  1. Find all connected components
  2. Detect cycle using DFS
  3. Implement topological sort
  4. Find MST cost using Prim/Kruskal
  5. Compute transitive closure
  6. Shortest path from 0 to all
  7. Bipartite check using BFS

12. Key Takeaways

ConceptInsight
Adjacency ListBest for sparse graphs
BFSShortest path in unweighted
DFSCycle, path existence
PrimGrows from vertex
KruskalSorts all edges
WarshallAll-pairs reachability
DijkstraNon-negative weights only

End of Notes