Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 4

Adjacency Matrix Representation in C++

Recommended resources

Introduction

In our last lesson, we established the fundamental vocabulary for describing graph structures, defining concepts like paths, cycles, and connected components. These are the abstract properties of a graph. Now, we will bridge the gap from theory to practice by exploring how to represent these abstract structures in a way a computer can understand and manipulate. Your goal for this lesson is to learn how to represent a graph using an adjacency matrix in C++.

This is the first of two primary methods we will study for storing graphs. Mastering this representation is crucial, as it forms the basis for certain algorithms and provides a clear conceptual starting point. Your experience with 2D arrays in C++ will be directly applicable here, as we essentially map the relationships between vertices onto a grid.


The Concept of an Adjacency Matrix

At its core, a graph is a collection of vertices and the edges that connect them. An adjacency matrix is a straightforward way to encode this information. For a graph with vertices (let's say they are numbered from 0 to ), we can create a square matrix.

Let's call this matrix adj. The rule is simple:

  • adj[i][j] contains a value indicating the nature of the edge from vertex i to vertex j.

For a simple, unweighted graph, this value is typically a boolean (0 or 1):

  • adj[i][j] = 1 if an edge exists from i to j.
  • adj[i][j] = 0 if no edge exists from i to j.

To see this in action, take a look at the helpful summary image below. Focus on the top-left (Undirected Unweighted) and bottom-left (Directed Unweighted) examples.

This image shows four common graph types and their corresponding adjacency matrix and adjacency list representations. Compare the visual graph drawing with its matrix equivalent.

Notice two key properties visible in the "Graph Representation" image:

  1. Undirected Graphs: The adjacency matrix for an undirected graph is always symmetric. If there is an edge between 0 and 1, then adj[0][1] = 1 and adj[1][0] = 1. The matrix is a mirror image across its main diagonal (from top-left to bottom-right).
  2. Directed Graphs: The matrix is not necessarily symmetric. An edge from 0 to 1 means adj[0][1] = 1, but this tells us nothing about adj[1][0]. A 0 there would mean the edge is one-way.

Implementation in C++

Now, let's translate this concept into code. In competitive programming, graph problems typically provide input in a standard format. A very popular format, which you'll see on platforms like Codeforces and AtCoder, is to first give you the number of vertices and the number of edges , followed by lines, each describing one edge.

The take U forward video provides an excellent explanation of this common input structure and how to begin building a representation from it.

G-2. Graph Representation in C++ | Two Ways to Represent

This video by take U forward, a renowned competitive programming channel, breaks down how graphs are described in problems and how to conceptually build an adjacency matrix.

First, watch from the beginning to understand the standard input format for graph problems. Then, continue watching from the next segment, which explains how to translate these edges into a 2D matrix, covering both undirected and directed cases conceptually. Pay attention to the idea of 1-based versus 0-based indexing for vertices.

With that conceptual understanding, let's look at a practical C++ implementation. In C++, we typically use a vector<vector<int>> to create a dynamic 2D array for our matrix.

The following reading provides a concise, competitive-programming-focused code snippet for building an adjacency matrix from standard input.

Graph Input Methods for Competitive Programming | Data Structures ...

This article provides clean, efficient C++ code for common graph input scenarios. We'll focus on the adjacency matrix method.

Please read the section titled "Method 1: Adjacency Matrix". Note how the code handles both directed and undirected graphs. The commented line adj[v][u] = 1; is the only difference.

As you see in the code, after reading the number of vertices n and edges m, you initialize an n x n matrix (or (n+1) x (n+1) for 1-based indexing) with zeros. Then, you loop m times. In each iteration, you read a pair of vertices u and v that form an edge and set adj[u][v] = 1. For an undirected graph, you also set adj[v][u] = 1 to maintain symmetry.


Representing Weighted Graphs

The adjacency matrix concept extends naturally to weighted graphs. Instead of storing a 1 to indicate an edge's existence, you store the edge's weight.

What if there is no edge between two vertices? We need a special value to signify this. Using 0 is risky, as an edge could legitimately have a weight of 0. A common practice in competitive programming is to initialize the matrix with a very large value, representing infinity (INF). The distance from a node to itself, adj[i][i], is always 0.

This approach is detailed in the next section of the same article.

Graph Input Methods for Competitive Programming | Data Structures ...

This section extends the previous example to handle weighted graphs.

Read the section titled "Method 2: Weighted". Observe the initialization with INF and the assignment of the weight w to the matrix cell.


Analysis: Strengths and Weaknesses

Choosing the right data structure is about understanding trade-offs. The adjacency matrix has clear advantages and disadvantages that you must consider.

Space Complexity:
The most significant drawback of the adjacency matrix is its space requirement. For a graph with vertices, it always consumes memory, regardless of how many edges the graph has. If , a matrix would require approximately bytes = 40 GB of memory, which is far beyond the typical memory limits (256-512 MB) in programming contests.
Therefore, an adjacency matrix is only feasible for dense graphs (where the number of edges is close to ) or when is small (e.g., ).

The take U forward video makes this point very clearly.

G-2. Graph Representation in C++ | Two Ways to Represent

This short clip explains the space complexity of the adjacency matrix.

Watch from this timestamp to understand the O(N²) space complexity and why it can be costly.

Time Complexity:
The adjacency matrix shines in one key operation: checking for an edge.

  • Check for an edge (u, v): This is an operation. You can simply access adj[u][v] and see if it's non-zero (or not INF for weighted graphs).
  • Iterate through all neighbors of a vertex u: This is an operation. To find all vertices connected to u, you must traverse the entire u-th row of the matrix. This is inefficient for sparse graphs (where is much smaller than ), as you might scan many zeros to find just a few neighbors.

The table in the resource Graph Input Methods summarizes this trade-off. We will revisit this table in a future lesson, but for now, focus on the first row.

Graph Input Methods for Competitive Programming | Data Structures ...

This table provides a high-level comparison of different graph representations.

Find the table under the heading "When to Use Each Method". Examine the row for "Adjacency Matrix" to consolidate your understanding of its space/time characteristics and best use cases.


Conclusion

In this lesson, you have learned how to translate the abstract idea of a graph into a concrete C++ data structure: the adjacency matrix. We have seen how this simple 2D array can represent directed, undirected, weighted, and unweighted graphs.

Key Takeaways:

  • An adjacency matrix is a grid where adj[i][j] stores information about the edge from vertex i to vertex j.
  • In C++, this is typically implemented with vector<vector<int>>.
  • Undirected graphs produce a symmetric matrix, while directed graphs may not.
  • Weighted graphs store edge weights in the matrix, using an "infinity" value to represent the absence of an edge.
  • The primary strength of the adjacency matrix is its time complexity for checking the existence of an edge.
  • Its primary weakness is its space complexity, which makes it unsuitable for graphs with a large number of vertices.

This final point about space complexity is critical. For many problems in competitive programming where the number of vertices is large but the number of edges is relatively small (a sparse graph), the adjacency matrix is not a viable option. This motivates the need for our next topic: the adjacency list, a more memory-efficient way to represent graphs, which we will cover in the next lesson.