skip to content

Why can an adjacency matrix beat a list on 300 sensors where nearly every pair is linked?

level: seniorimportance: nice to knowfreq 34%

answer

  1. check whether the asymptotic gap still exists
  2. at this density both layouts are quadratic
  3. 300 squared is only 90,000 cells
  4. one bit per pair, rows contiguous in cache
  5. small V plus pair-shaped queries

basics

~20 s

At that density both layouts are O(V^2), so constants decide. The matrix is 90,000 contiguous cells — a few kilobytes packed as bits — with no per-edge record overhead, direct O(1) pair tests and rows that stream through cache.

solid answer

~50 s

With 300 sensors and nearly every pair correlated, E is about 45,000 undirected links, which is proportional to V^2 — so the adjacency list's O(V+E) and the matrix's O(V^2) are the *same* asymptotic class, and the asymptotic argument for lists evaporates. What is left is constants. The matrix is 90,000 cells laid out contiguously: about 11 KB packed one bit per cell, 90 KB at a byte, either way resident in cache. The list stores each link twice, 90,000 neighbor entries plus 300 container headers plus per-entry overhead, scattered across memory. Correlation workloads also probe specific pairs and scan whole rows, which is exactly what the matrix is good at. The decision is not density alone: it is that V is small enough for V^2 to be trivial *and* the workload is pair-oriented rather than neighbor-walk-oriented.

go deeper

for a junior

Recall that the usual advice to prefer adjacency lists rests on the graph being sparse. When almost every pair is linked, the edge count is already proportional to V^2 and that advantage disappears.

for a middle

Explain that O(V+E) and O(V^2) collapse into the same class once E is proportional to V^2, then compare the actual storage: contiguous cells with no per-edge overhead against doubled neighbor entries plus per-vertex container overhead.

for a senior

Demonstrate that you check absolute numbers and access patterns, not just bounds: 90,000 cells fit in cache, pair tests are direct, row scans stream. State the conditions that would reverse the choice rather than defending the matrix on density alone.

for a principal

Own the durability of the decision: whether the density is real or an artifact of not filtering, how it behaves at ten times the sensor count, and whether an unusual choice is one the team will maintain correctly. Say what evidence would trigger revisiting it.

## The default is a default, not a law "Use an adjacency list" is right for most real graphs because most real graphs are sparse — E close to a constant multiple of V. The reasoning behind the default is an asymptotic gap: O(V+E) beats O(V^2) badly when E is far below V^2. A candidate who repeats the default without the reasoning cannot notice when the premise fails, and this scenario is where it fails. ## Working the numbers A sensor-correlation network with V = 300, where nearly every pair shows a meaningful correlation, has E of roughly V*(V-1)/2, about 45,000 undirected links. Now E *is* proportional to V^2, so: - Matrix: 300 * 300 = 90,000 cells. As one bit per cell, about 11 KB. As one byte, 90 KB. As four-byte correlation coefficients, 360 KB. - Adjacency list: each undirected link is stored in both endpoints' slots, so 90,000 neighbor entries, plus 300 per-vertex containers with their headers and spare capacity, plus per-entry overhead if each entry carries a neighbor id and a weight. O(V+E) with E = 45,000 and O(V^2) with V = 300 are the same order of magnitude of stored items. The asymptotic tiebreaker is gone; whatever decides this is below the notation. ## What decides below the notation **Bytes per relationship.** The matrix's per-pair cost can be a single bit for an unweighted graph — the smallest possible encoding of "related or not". A list entry cannot be smaller than a vertex identifier, typically 16 to 32 bits, and it appears twice per undirected link. Packing the matrix as bit rows gives roughly an eightfold cut over one byte per cell and puts more of the graph in cache at once. **Contiguity.** A matrix row is a sequential run of memory, so a full row scan is a streaming read that hardware prefetching handles perfectly. A list built from per-vertex containers scatters its entries; walking neighbors chases references and can miss cache repeatedly. At 11 KB the whole matrix fits in a modern core's first-level cache with room to spare, and at 90 KB it fits comfortably in second-level cache — the entire graph, resident. **Query shape.** Correlation analysis tends to ask about *pairs* — is A related to B, how strong — and to sweep rows looking for the strongest partner of each sensor. The matrix answers a pair test with one direct index, O(1) worst case, and a row sweep is O(V) over contiguous memory. On a dense list, the equivalent pair test is O(deg(u)), and deg(u) here is around 300: no better than the matrix's row scan, and slower per element. **Simplicity.** A fixed grid has no per-vertex allocation, no growth, and no reallocation during construction. It is also the easier structure to hand to the next engineer, which matters when the clever choice has to survive a team. ## The honest counterweights Density alone does not decide anything; two conditions must hold together. First, **V must be small enough that V^2 is trivial**. Three hundred sensors gives 90,000 cells, nothing at all. Thirty thousand sensors gives 9*10^8 cells — hundreds of megabytes even packed as bits, and the answer flips. This matters because density and scale usually move in opposite directions: as a network grows, the fraction of pairs that are genuinely related tends to fall, so the very largest graphs are almost always the sparsest. Second, **the workload must be pair-oriented or scan-oriented**. If the real query is "walk the neighbors of a handful of interesting sensors", the list wins even here, because it touches deg(u) entries where the matrix touches V cells. Third, **density may be an artifact of not filtering**. "Nearly every pair is correlated" often means every pair has a nonzero coefficient, most of them noise. Threshold at a meaningful correlation strength and the graph may collapse to a few links per sensor — sparse again, and back to the list. Ask whether the density is real before you build for it. ## The answer to give Do not defend the matrix by saying "it's dense". Defend it by stating the three things you checked: E is proportional to V^2 so the asymptotic argument is a tie; V^2 is small in absolute terms so the memory is free; the workload probes pairs and scans rows so the layout matches the access pattern. Then name what would change your mind — a tenfold growth in sensors, or a filtering step that makes the graph sparse — because a representation choice that cannot say what would reverse it is not a judgment, it is a preference.

  • What would make you switch back to an adjacency list at this density?
    Two things. Growth: at 30,000 sensors the grid is 9*10^8 cells, hundreds of megabytes even as packed bits, and density usually falls as a network grows, so the premise dies with scale. Or a change in query shape: if the real work is walking the neighbors of a few interesting sensors rather than probing pairs, the list touches deg(u) entries where the matrix walks a full row of V.
  • Is "nearly every pair is linked" always a real property?
    Often not. Correlation data usually gives every pair a nonzero coefficient, most of it noise, which looks dense but is not meaningfully so. Apply a strength threshold before choosing a representation: if only links above the cutoff count, the graph may collapse to a handful per sensor and become sparse, at which point the matrix is 90,000 cells storing a few thousand real relationships and the list is the right call again.
  • What does packing the matrix as bit rows actually buy?
    For an unweighted dense graph it cuts memory roughly eightfold against one byte per cell, so more of the graph stays resident in cache and row scans stream faster. It does not change the O(V^2) bound — that is fixed by the layout — and it only works when a cell needs a single yes-or-no bit. The moment you need to store a correlation strength per pair, cells widen and the saving disappears.

A wall chart with a box for every pair of names is wasteful in a stadium and perfect in a small room where nearly every box gets filled in.

saying these in an interview costs you the question

  • Says adjacency lists are always the better representation
  • Ignores that at this density both bounds are quadratic
  • Compares only asymptotics when the classes are equal
  • Assumes the choice scales to a much larger sensor count
  • Treats every nonzero correlation as a real edge

context