C Data Structures: Graph Representations, BFS & DFS Traversals Masterclass
Welcome to Phase 18 (Chapter 50): C Data Structures โ Graph Representations, BFS & DFS Traversals Masterclass! Graphs model relationships between entities: social networks, road maps, dependency trees, and state machines. In C, graphs are typically represented as adjacency matrices or adjacency lists implemented with arrays of linked lists.
| Term | Definition |
|---|---|
| Vertex (Node) | A point in the graph (city, user, state). |
| Edge | A connection between two vertices (road, friendship, transition). |
| Directed Graph | Edges have direction: AโB does not imply BโA. |
| Undirected Graph | Edges are bidirectional: AโB implies both AโB and BโA. |
| Weighted Graph | Each edge has a numeric weight (distance, cost, bandwidth). |
| Degree | Number of edges incident to a vertex. |
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_V 10
typedef struct EdgeNode {
int to;
struct EdgeNode *next;
} EdgeNode;
typedef struct {
EdgeNode *adj[MAX_V];
int V;
} Graph;
Graph *graph_create(int V) {
Graph *g = calloc(1, sizeof(Graph));
g->V = V;
return g;
}
void graph_add_edge(Graph *g, int u, int v) {
EdgeNode *e = malloc(sizeof(EdgeNode));
e->to = v; e->next = g->adj[u]; g->adj[u] = e;
/* Undirected: add reverse edge too */
EdgeNode *e2 = malloc(sizeof(EdgeNode));
e2->to = u; e2->next = g->adj[v]; g->adj[v] = e2;
}
void bfs(const Graph *g, int start) {
int visited[MAX_V] = {0};
int queue[MAX_V], front = 0, rear = 0;
visited[start] = 1;
queue[rear++] = start;
printf("BFS from %d: ", start);
while (front < rear) {
int u = queue[front++];
printf("%d ", u);
for (EdgeNode *e = g->adj[u]; e; e = e->next) {
if (!visited[e->to]) {
visited[e->to] = 1;
queue[rear++] = e->to;
}
}
}
printf("\n");
}
static int dfs_visited[MAX_V];
void dfs(const Graph *g, int u) {
dfs_visited[u] = 1;
printf("%d ", u);
for (EdgeNode *e = g->adj[u]; e; e = e->next)
if (!dfs_visited[e->to]) dfs(g, e->to);
}
int main(void) {
Graph *g = graph_create(6);
graph_add_edge(g, 0, 1);
graph_add_edge(g, 0, 2);
graph_add_edge(g, 1, 3);
graph_add_edge(g, 2, 4);
graph_add_edge(g, 3, 5);
bfs(g, 0);
memset(dfs_visited, 0, sizeof(dfs_visited));
printf("DFS from 0: ");
dfs(g, 0);
printf("\n");
return 0;
}Q1: When to use adjacency matrix vs adjacency list?
Matrix: O(1) edge lookup, O(Vยฒ) space โ good for dense graphs. List: O(V+E) space โ good for sparse graphs where V >> E.
Q2: What does BFS guarantee that DFS does not?
BFS guarantees finding the shortest path (fewest edges) between source and any reachable node in an unweighted graph. DFS does not guarantee shortest path.
Q3: How do you detect cycles in a directed graph?
Use DFS with a "currently in recursion stack" boolean array. If DFS revisits a node currently in the stack, a cycle exists.
Q4: What is topological sort?
A linear ordering of vertices in a Directed Acyclic Graph (DAG) such that for every edge uโv, u appears before v. Used for build systems, task scheduling, and dependency resolution.
Q5: What are connected components?
Groups of vertices where every vertex can reach every other vertex in the group. Found by running BFS/DFS from each unvisited vertex, counting how many times a new search starts.