Skip to content

Graphs and how to store them

A graph is vertices joined by edges, stored as a V × V adjacency matrix of yes-or-no cells or as a list of neighbours for each vertex.

Helps to know first
This topic

First, the picture

Six vertices joined by seven edges, stored twice. Watch each edge set two cells of a grid and add a node to two lists.

Two ways to store a network

Six vertices and seven edges as a matrix and as lists

static void push_arc(struct enode **list, int u, int v){    struct enode *e = malloc(sizeof *e);    if (e == NULL)        exit(1);    e->to = v;    e->next = list[u];    list[u] = e;} static void add_edge(int adj[V][V], struct enode **list, int u, int v){    adj[u][v] = 1;    adj[v][u] = 1;    push_arc(list, u, v);    push_arc(list, v, u);} int main(void){    const int edges[E][2] = { { 4, 5 }, { 3, 4 }, { 2, 4 }, { 1, 3 }, { 1, 2 }, { 0, 2 }, { 0, 1 } };    int adj[V][V] = { { 0 } };    struct enode *list[V] = { NULL };    for (int i = 0; i < E; i++)        add_edge(adj, list, edges[i][0], edges[i][1]);#ifdef EXTRA_U    add_edge(adj, list, EXTRA_U, EXTRA_V);#endif    for (int u = 0; u < V; u++) {        for (int v = 0; v < V; v++)            printf("%d ", adj[u][v]);        printf("|");        int degree = 0;        for (const struct enode *p = list[u]; p != NULL; p = p->next) {            printf(" %d", p->to);            degree++;        }        printf("  (degree %d)\n", degree);    }

Six vertices, 0 to 5, and seven edges, listed from the last back to the first.

edges
0
matrix
36 cells, 144 bytes
lists
0 nodes
none

Output

0.00 / 14.95 s
Describe this picture

The picture has three parts. On the left, on a wide screen, is the graph: six numbered circles, the vertices 0 to 5, with 0 at the left, 1 and 3 along the top, and 2, 4 and 5 along the bottom; edges appear as lines between them. On the right is a 6 × 6 grid, int adj[6][6], with the row and column numbers beside it; every cell starts at 0. Under both are six rows, list[0] to list[5], each a head with a chain of nodes to its right, joined by arrows; each node shows one vertex number. On a phone the three parts are stacked. Under the picture are the lines of graph.c the clip runs, with the line about to run marked, one sentence on the current step, three readouts (the edges stored, the matrix’s size, and the list nodes), the control, and the output. The clip plays once, about 15 seconds. The seven edges are added in the order 4–5, 3–4, 2–4, 1–3, 1–2, 0–2 and 0–1. For each, its two ends are ringed and its line appears; two cells of the grid turn to 1 and light, mirror images across the diagonal, such as row 4 column 5 and row 5 column 4; then a node joins the front of each of the two lists, 5 in list 4 and 4 in list 5, toned. By the end the lists read 1 2; 0 2 3; 0 1 4; 1 4; 2 3 5; and 4, each in ascending order. Then each vertex is printed in turn: its circle is ringed, its row of the grid lights, and “deg” with its degree appears beside it. The clip rests on the output, six lines of a matrix row, a bar and a list, ending 0 0 0 0 1 0 | 4 (degree 1). The control, “Extra edge”, is a slider from “none” through the 8 pairs not yet joined, from 0–3 to 3–5: a new pair replays the clip with that edge added last, two more cells set and two more nodes on the fronts of their lists. The transport plays and pauses, steps one beat back or forward, and scrubs; a paused step is kept in the page address as graph.step, and the extra edge as graph.extra.

Vertices and edges

A graph is a set of vertices joined by edges. A road map is a graph: the junctions are vertices, the roads edges. This one has V = 6 vertices and E = 7 edges, 0–1, 0–2, 1–2, 1–3, 2–4, 3–4 and 4–5: a triangle, a square and a tail.

  • In an undirected graph an edge goes both ways. In a directed graph each edge is an arc from one vertex to another, like a one-way street.
  • In a weighted graph each edge carries a number: a length, a cost, a time.
  • The degree of a vertex is the number of edges at it. Vertex 4 has degree 3. Each edge has two ends, so the degrees add up to 2E: here 2 + 3 + 3 + 2 + 3 + 1 = 14.
  • A path is a sequence of vertices, each joined to the next, such as 0, 2, 4, 5. A cycle is a path that returns to its start, such as 1, 2, 4, 3, 1.
  • A graph is connected when there is a path between every two vertices.

The code and its cost

The adjacency matrix

The first store is a V × V grid of int cells. Cell adj[u][v] is 1 when u and v are joined and 0 when they are not:

int adj[V][V] = { { 0 } };

add_edge stores an undirected edge in both directions, so the matrix is symmetric across its diagonal:

adj[u][v] = 1;
adj[v][u] = 1;

An undirected edge is stored twice, in row u and in row v. Testing for an edge reads one cell, one step. Listing the neighbours of u reads the whole of row u, V cells, whatever the degree. The matrix takes V² cells, joined or not: 36 ints, 144 bytes, in main’s frame.

Adjacency lists

The second store gives each vertex a list of its neighbours, as a linked list of nodes:

struct enode {
    int to;
    struct enode *next;
};

struct enode *list[V] = { NULL };

A node holds one neighbour, 16 bytes: an int, 4 bytes of padding and a pointer. push_arc puts a new node on the front of a list, and add_edge calls it twice, once for each end:

push_arc(list, u, v);
push_arc(list, v, u);

An undirected edge again takes two entries, one node in each list: 7 edges make 14 nodes. The program adds the edges from the last back to the first, so pushing on the front leaves every list in ascending order. Listing u’s neighbours follows u’s list, as many steps as its degree. Testing for an edge u–v walks u’s list, also up to its degree.

The printed table

The program prints each vertex’s matrix row, then its list and its degree:

0 1 1 0 0 0 | 1 2  (degree 2)
1 0 1 1 0 0 | 0 2 3  (degree 3)
1 1 0 0 1 0 | 0 1 4  (degree 3)
0 1 0 0 1 0 | 1 4  (degree 2)
0 0 1 1 0 1 | 2 3 5  (degree 3)
0 0 0 0 1 0 | 4  (degree 1)

Vertex 5 is in only one list, 4’s.

Space and steps

MeasureAdjacency matrixAdjacency lists
SpaceV² cellsV heads and 2E nodes
Is u–v an edge?1 stepup to u’s degree
List u’s neighboursV stepsu’s degree

Here the matrix is the smaller store: 144 bytes against 14 blocks of 32 bytes, 448 bytes of heap, as malloc gives each 16-byte node.

Sparse and dense

A graph is sparse when E is close to V, and dense when E is close to V(V − 1)/2, every pair joined. Road maps and social networks are sparse: a junction meets a few roads, whatever the size of the map. For them the lists win: their space grows with the edges, the matrix’s with the square of the vertices. A small dense graph suits the matrix, with its one-step edge test.

The matrix is the adjacency matrix of linear algebra, where its powers count paths. Packed into arrays, adjacency lists become the compressed-row form of a sparse matrix.

Running it yourself

gcc -std=c11 -Wall -Wextra -pedantic graph.c -o graph
./graph
gcc -std=c11 -Wall -Wextra -pedantic -DEXTRA_U=0 -DEXTRA_V=5 graph.c -o graph
./graph

The second build adds the edge 0–5: two more cells turn to 1, and 5 and 0 join the fronts of lists 0 and 5.

Worked example

A road map. A map with 1,000,000 junctions and 2,500,000 roads. As a matrix: 10¹² cells, 125 GB even at one bit a cell. As lists: 5,000,000 nodes, about 160 MB in the 32-byte blocks malloc gives them (80 MB of node data), and 8 MB of heads.

This graph. With V = 6 the matrix is 144 bytes and the lists 448 bytes of heap: the matrix is not always the bigger store.

Arcs. In a directed graph with arcs 0 → 1 and 1 → 2, each arc sets one cell and adds one node: adj[0][1] and adj[1][2], a 1 in list 0 and a 2 in list 1. The matrix is no longer symmetric.

Three checks. Which list holds vertex 5? (Only 4’s.) How many steps to list the neighbours of 4 in each store? (6 matrix cells; 3 list nodes.) A graph on 10 vertices with every pair joined: how many list nodes? (90.)

Where it’s used

Maps and transport. Road and rail networks are sparse graphs, kept as adjacency lists for route planning.

Social networks. People are vertices and friendships edges; each person’s list holds their friends.

Dependencies. Tasks that must wait for other tasks form a directed graph, such as files that must be compiled before others.

Circuits and the web. Components joined by wires, and pages joined by links, are graphs.

Reference card

Code or ideaMeaning
V, Ethe numbers of vertices and edges
degrees add to 2Eeach edge has two ends
adj[u][v] = 1; adj[v][u] = 1;an undirected edge in the matrix: two cells
push_arc(list, u, v); push_arc(list, v, u);the same edge in the lists: two nodes
V² cellsthe matrix’s space, edges or not
V heads, 2E nodesthe lists’ space
1 step, or the degreean edge test in the matrix, or in a list

Platform: C11, gcc on x86-64 Linux: int 4 bytes, pointers 8, little-endian. Addresses in the pictures are short stand-ins, by one rule for the whole course; sizes are the real ones.

Keep reading with a free account.

Graphs is a members’ section. An account costs nothing.

By creating an account you accept the terms of use.

Sign in

Already have an account? Use the way you signed up.

Are you 13 or over?

Accounts and email updates are for people aged 13 or over. We keep only your answer, never your date of birth.

End of the lesson

Where to go next.

New lessons by email

Are you 13 or over?

Accounts and email updates are for people aged 13 or over. We keep only your answer, never your date of birth.

Phasorium

Account

Sign inWith Google, GitHub or your email

Subjects

Site

Look