Your Progress
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
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
A | B | C | D | E | |
---|---|---|---|---|---|
A | 0 | 1 | 1 | 0 | 0 |
B | 1 | 0 | 1 | 1 | 0 |
C | 1 | 1 | 0 | 0 | 1 |
D | 0 | 1 | 0 | 0 | 1 |
E | 0 | 0 | 1 | 1 | 0 |
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
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>45// Define the maximum number of vertices6#define MAX_VERTICES 10078// Graph represented as an adjacency list9typedef struct {10 int vertices; // Number of vertices11 int* adjacencyList[MAX_VERTICES]; // Array of adjacency lists12 int size[MAX_VERTICES]; // Size of each adjacency list13 int capacity[MAX_VERTICES]; // Capacity of each adjacency list14} Graph;1516// Initialize a graph with n vertices17Graph* createGraph(int vertices) {18 Graph* graph = (Graph*)malloc(sizeof(Graph));19 graph->vertices = vertices;2021 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 }2627 return graph;28}2930// Add an edge to the graph (for undirected graph)31void addEdge(Graph* graph, int src, int dest) {32 // Add edge from src to dest33 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;3839 // 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}4647// Print the adjacency list representation of the graph48void 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}5758// Free the memory allocated for the graph59void freeGraph(Graph* graph) {60 for (int i = 0; i < graph->vertices; i++) {61 free(graph->adjacencyList[i]);62 }63 free(graph);64}6566// Driver program67int main() {68 // Create a graph with 5 vertices (labeled 0 to 4)69 Graph* graph = createGraph(5);7071 // Add edges to the graph72 addEdge(graph, 0, 1); // A - B73 addEdge(graph, 0, 2); // A - C74 addEdge(graph, 1, 2); // B - C75 addEdge(graph, 1, 3); // B - D76 addEdge(graph, 2, 4); // C - E77 addEdge(graph, 3, 4); // D - E7879 // Print the adjacency list representation80 printGraph(graph);8182 // Free allocated memory83 freeGraph(graph);8485 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:
- Breadth-First Search-Learn how to traverse a graph level by level
- Depth-First Search-Discover how to explore a graph by going as deep as possible
- Shortest Path Algorithms-Master algorithms for finding the optimal path between vertices
Related Tutorials
Breadth-First Search
Learn how to traverse a graph level by level using BFS.
Learn moreDepth-First Search
Explore how to traverse a graph by going as deep as possible using DFS.
Learn moreShortest Path Algorithms
Learn algorithms for finding the shortest path in a graph.
Learn more