Pulsars
0 %
Log inSign up

Modelling with a graph

Two ways to store it in memory

The problem: how to encode "who is connected to whom"

A graph does not have the ready-made structure of a tree. To put it in memory, there are two main representations, with opposite trade-offs. Let's take this small undirected graph as an example:

        (A)------(B)
         |        |
         |        |
        (C)------(D)

Neighbourhoods: A: B,CB: A,DC: A,DD: B,C.

Representation 1: the adjacency matrix

We build a square table: the cell (row X, column Y) is 1 if there is an edge between X and Y, and 0 otherwise.

        A   B   C   D
      +---+---+---+---+
  A   | 0 | 1 | 1 | 0 |
      +---+---+---+---+
  B   | 1 | 0 | 0 | 1 |
      +---+---+---+---+
  C   | 1 | 0 | 0 | 1 |
      +---+---+---+---+
  D   | 0 | 1 | 1 | 0 |
      +---+---+---+---+

For an undirected graph, the matrix is symmetric (the edge A-B appears at (A,B) and at (B,A)).

sommets = ["A", "B", "C", "D"]
matrice = [
    [0, 1, 1, 0],   # A
    [1, 0, 0, 1],   # B
    [1, 0, 0, 1],   # C
    [0, 1, 1, 0],   # D
]
# "Are A and D connected ?"  ->  matrice[0][3] == 0  -> no

Advantage: knowing whether two vertices are connected is immediate (a single cell to read). Disadvantage: the matrix takes up n x n cells, even if the graph has very few edges. For a social network of millions of people, this is unmanageable.

Representation 2: the adjacency list

For each vertex, we simply store the list of its neighbours. In Python, a dictionary is perfectly suited to this.

graphe = {
    "A": ["B", "C"],
    "B": ["A", "D"],
    "C": ["A", "D"],
    "D": ["B", "C"],
}
# the neighbours of B ?  ->  graphe["B"]  ->  ['A', 'D']

Advantage: we store only the edges that exist. For a graph with low density (few edges relative to the number of vertices), this is infinitely more economical. Disadvantage: to know whether A and D are connected, we must scan the list of A's neighbours.

Which one to choose?

   Many edges ("dense" graph)            ->  adjacency matrix
   Few edges ("sparse" graph)            ->  adjacency list
Criterion Matrix List
Memory used n x n n + edges
Test an edge X-Y immediate scan neighbours
List a vertex's neighbours scan 1 row immediate

In practice, most real graphs (social networks, roads) are sparse: so we almost always use the adjacency list. It is the one we will use for traversals.

In summary

Two representations coexist. The adjacency matrix answers "are these two vertices connected?" instantly but wastes n x n cells. The adjacency list stores only the real edges and gives the neighbours directly — it is the default choice for sparse graphs, and therefore for almost all real graphs.