Your Progress

12/30 completed

40% complete. Continue learning to master DSA!

Graph Data Structures

Graphs are versatile data structures that represent relationships between objects. They consist of vertices (nodes) connected by edges, allowing us to model complex networks, maps, social connections, and much more.

💡 Key Takeaways

  • Graphs consist of vertices (nodes) and edges that connect them
  • Graphs can be directed (one-way connections) or undirected (two-way connections)
  • Common graph representations include adjacency matrices, adjacency lists, and edge lists
  • Key graph algorithms include traversals (BFS/DFS), shortest path algorithms, and minimum spanning trees
  • Graphs are used in social networks, mapping applications, recommendation systems, and more

What is a Graph?

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

  • Vertices (or Nodes): The fundamental units of a graph
  • Edges: The connections between vertices

Formally, a graph G can be defined as an ordered pair G = (V, E) where:

  • V is a set of vertices
  • E is a set of edges connecting the vertices in V

Simple Undirected Graph

A
B
C
D
E

This undirected graph has 5 vertices (A, B, C, D, E) and 6 edges connecting them.

Types of Graphs

Graphs come in various forms, each suited for different types of problems:

Directed vs. Undirected

Directed Graph (Digraph): Edges have a direction, indicating a one-way relationship.

Undirected Graph: Edges have no direction, representing a two-way relationship.

Weighted vs. Unweighted

Weighted Graph: Edges have associated weights or costs.

Unweighted Graph: All edges have equal importance or weight.

Cyclic vs. Acyclic

Cyclic Graph: Contains at least one cycle (a path that starts and ends at the same vertex).

Acyclic Graph: Has no cycles.

Connected vs. Disconnected

Connected Graph: There is a path between every pair of vertices.

Disconnected Graph: There is at least one pair of vertices with no path between them.

Special Types of Graphs

  • Complete Graph: Every vertex is connected to every other vertex.
  • Bipartite Graph: Vertices can be divided into two disjoint sets, with edges only between sets.
  • Tree: A connected, acyclic, undirected graph.
  • DAG (Directed Acyclic Graph): A directed graph with no cycles.

Graph Terminology

  • Degree: Number of edges connected to a vertex.
  • Path: Sequence of vertices where each adjacent pair is connected by an edge.
  • Cycle: A path that starts and ends at the same vertex.
  • Connected Component: A subset of vertices where there is a path between any two vertices.

Real-World Graph Examples

Many real-world systems can be modeled as graphs: social networks (where users are vertices and connections are edges), road networks (where intersections are vertices and roads are edges), the internet (where devices are vertices and connections are edges), and even molecules (where atoms are vertices and bonds are edges).

Graph Representations

There are several ways to represent graphs in computer memory, each with its own advantages and disadvantages:

1. Adjacency Matrix

An adjacency matrix is a 2D array of size V×V (where V is the number of vertices) where:

  • matrix[i][j] = 1 (or weight) if there is an edge from vertex i to vertex j
  • matrix[i][j] = 0 if there is no edge from vertex i to vertex j

Example Adjacency Matrix

ABCDE
A01100
B10110
C11001
D01001
E00110

Advantages

  • Simple to implement and follow
  • Edge lookup is O(1)
  • Adding/removing an edge is O(1)
  • Good for dense graphs

Disadvantages

  • Uses O(V²) space regardless of the number of edges
  • Inefficient for sparse graphs
  • Finding all adjacent vertices is O(V)

2. Adjacency List

An adjacency list represents a graph as an array of linked lists:

  • The array index represents a vertex
  • Each entry in the array contains a list of the vertex's adjacent vertices

Example Adjacency List

A
B
C
B
A
C
D
C
A
B
E
D
B
E
E
C
D

Advantages

  • Space efficient for sparse graphs (uses O(V+E) space)
  • Finding all adjacent vertices is efficient
  • Adding a vertex is easier

Disadvantages

  • Edge lookup is O(degree of vertex), which can be O(V) in the worst case
  • More complex to implement compared to adjacency matrix
  • Removing edges can be more complex

Note: The choice of representation depends on the characteristics of your graph and the operations you need to perform. Adjacency lists are generally preferred for sparse graphs (where E is much smaller than V²), while adjacency matrices can be better for dense graphs.

Graph Implementation

Let's implement a graph data structure using an adjacency list representation, which is the most common implementation for most real-world applications:

1#include <stdio.h>
2#include <stdlib.h>
3#include <stdbool.h>
4
5// Define the maximum number of vertices
6#define MAX_VERTICES 100
7
8// Graph represented as an adjacency list
9typedef struct {
10 int vertices; // Number of vertices
11 int* adjacencyList[MAX_VERTICES]; // Array of adjacency lists
12 int size[MAX_VERTICES]; // Size of each adjacency list
13 int capacity[MAX_VERTICES]; // Capacity of each adjacency list
14} Graph;
15
16// Initialize a graph with n vertices
17Graph* createGraph(int vertices) {
18 Graph* graph = (Graph*)malloc(sizeof(Graph));
19 graph->vertices = vertices;
20
21 for (int i = 0; i < vertices; i++) {
22 graph->adjacencyList[i] = (int*)malloc(sizeof(int));
23 graph->size[i] = 0;
24 graph->capacity[i] = 1;
25 }
26
27 return graph;
28}
29
30// Add an edge to the graph (for undirected graph)
31void addEdge(Graph* graph, int src, int dest) {
32 // Add edge from src to dest
33 if (graph->size[src] == graph->capacity[src]) {
34 graph->capacity[src] *= 2;
35 graph->adjacencyList[src] = (int*)realloc(graph->adjacencyList[src], graph->capacity[src] * sizeof(int));
36 }
37 graph->adjacencyList[src][graph->size[src]++] = dest;
38
39 // Add edge from dest to src (for undirected graph)
40 if (graph->size[dest] == graph->capacity[dest]) {
41 graph->capacity[dest] *= 2;
42 graph->adjacencyList[dest] = (int*)realloc(graph->adjacencyList[dest], graph->capacity[dest] * sizeof(int));
43 }
44 graph->adjacencyList[dest][graph->size[dest]++] = src;
45}
46
47// Print the adjacency list representation of the graph
48void printGraph(Graph* graph) {
49 for (int i = 0; i < graph->vertices; i++) {
50 printf("Adjacency list of vertex %d: ", i);
51 for (int j = 0; j < graph->size[i]; j++) {
52 printf("%d -> ", graph->adjacencyList[i][j]);
53 }
54 printf("NULL\n");
55 }
56}
57
58// Free the memory allocated for the graph
59void freeGraph(Graph* graph) {
60 for (int i = 0; i < graph->vertices; i++) {
61 free(graph->adjacencyList[i]);
62 }
63 free(graph);
64}
65
66// Driver program
67int main() {
68 // Create a graph with 5 vertices (labeled 0 to 4)
69 Graph* graph = createGraph(5);
70
71 // Add edges to the graph
72 addEdge(graph, 0, 1); // A - B
73 addEdge(graph, 0, 2); // A - C
74 addEdge(graph, 1, 2); // B - C
75 addEdge(graph, 1, 3); // B - D
76 addEdge(graph, 2, 4); // C - E
77 addEdge(graph, 3, 4); // D - E
78
79 // Print the adjacency list representation
80 printGraph(graph);
81
82 // Free allocated memory
83 freeGraph(graph);
84
85 return 0;
86}

Applications of Graphs

Graphs are incredibly versatile data structures with numerous real-world applications:

Social Networks

Users are represented as vertices, and relationships (friends, follows, etc.) are represented as edges. Graph algorithms help in finding mutual friends, suggesting new connections, and analyzing influence.

Web Graphs

Web pages are vertices, and hyperlinks are edges. Search engines use graph algorithms like PageRank to determine the importance of web pages and optimize search results.

Maps and Navigation

Locations are vertices, and roads are edges (often weighted by distance or time). Algorithms like Dijkstra's and A* are used to find the shortest or fastest routes between locations.

Recommendation Systems

Items and users are vertices, with edges representing preferences or interactions. Graph-based algorithms help recommend products, movies, music, and connections based on similarity patterns.

Computer Networks

Devices are vertices, and connections are edges. Graph algorithms help in routing protocols, network analysis, and optimizing data transmission paths.

Dependency Resolution

Software packages or tasks are vertices, and dependencies are edges. Topological sorting helps determine the order of installation or execution while satisfying all dependencies.

Key Graph Algorithms

To fully utilize graphs, familiarize yourself with key algorithms: Breadth-First Search, Depth-First Search, Dijkstra's Algorithm (shortest paths), Minimum Spanning Tree algorithms (Kruskal's, Prim's), and Topological Sort. These form the foundation for solving most graph-related problems efficiently.

Next Steps

Now that you understand graph data structures, here are some related topics to explore:

Related Tutorials

Breadth-First Search

Learn how to traverse a graph level by level using BFS.

Learn more

Depth-First Search

Explore how to traverse a graph by going as deep as possible using DFS.

Learn more

Shortest Path Algorithms

Learn algorithms for finding the shortest path in a graph.

Learn more