skip to content

Why does an array give O(1) access to any index — what address computation makes element 5,000,000 one step away?

level: juniorimportance: must knowfreq 85%

answer

  1. every cell is the same size
  2. no walking, only arithmetic
  3. base plus index times element size
  4. one multiply and one add, any index

basics

~20 s

An array stores equal-size elements contiguously, so the address of element i is base + i × element-size. That is one multiply and one add no matter how large i is, so element 5,000,000 costs the same as element 3.

solid answer

~40 s

An array is one contiguous block of memory holding elements of identical size. Because of that, the location of element `i` is fully determined by arithmetic: `address = base + i * element_size`. The computer performs one multiplication and one addition and reads that address directly — no traversal, no search, no dependence on `i`. That is the entire reason indexed access is O(1). The same math powers anything fixed-width: a binary file of 16-byte trade-tick records lets you seek straight to record 5,000,000 at offset 80,000,000. The two preconditions are the whole story — contiguity and equal element size. Give up either one and you need indirection (fixed-size references to variable-size data) or an offset table, and the price of keeping them is a fixed capacity reserved up front.

go deeper

for a junior

Be ready to state the formula — base + index × element size — and explain that contiguity plus equal element size is what makes it one step. This is a universal screener; answer it from the memory model, not from a memorized table.

for a middle

Explain why both preconditions are load-bearing: what breaks with scattered storage, what breaks with variable-size elements, and how fixed-size references restore O(1) indexing with one extra hop.

for a senior

Connect the idea beyond RAM — fixed-width record files, seek offsets — and show you budget memory at scale: capacity × element size decides RAM fit while access cost stays constant. Interviewers probe whether your O(1) claim survives a billion elements.

for a principal

Own the design conversation: when fixed-width layouts are worth imposing on a data model for computable addressing, and when the rigidity (fixed capacity, padded records) costs more than the constant-time access buys.

## The layout A static array is a single contiguous block of memory divided into cells of identical size. If the block starts at address `base` and each element occupies `element_size` bytes, then element `i` begins at: ``` address(i) = base + i * element_size ``` Nothing about this formula depends on the *contents* of the array or on how many elements precede `i`. Computing it is one multiplication and one addition — a fixed, tiny amount of work — and main memory (RAM, literally *random-access* memory) can then read or write that address directly. That is what O(1) random access means: the cost of reaching element `i` is a constant, independent of both `i` and the array's length. ## A worked example Suppose a market-data capture writes trade ticks as fixed-width 16-byte records: an 8-byte timestamp followed by an 8-byte price. Record 5,000,000 lives at `base + 5,000,000 × 16 = base + 80,000,000`. One multiply, one add, one read — the first 4,999,999 records are never touched. The same trick works on disk: a binary file of fixed-width records supports `seek(header + i * record_size)` to land on any record directly. Contrast a text file of variable-length lines: to find line 5,000,000 you must scan for newline characters, because no formula can tell you where a line starts when lines have different lengths. ## Why both preconditions matter **Contiguity.** If the elements were scattered around memory, knowing `i` would tell you nothing about where element `i` lives — you would need a lookup structure to find it, and consulting that structure is the very cost the array avoids. **Equal element size.** The multiplication `i * element_size` is only meaningful when every element occupies the same number of bytes. If elements varied in size, the position of element `i` would depend on the sizes of all elements before it — a running sum, which means either scanning or maintaining a separate offset table. Real systems that need arrays of variable-size things restore the invariant with indirection: store fixed-size *references* in the array and let each reference point to the variable-size data elsewhere. The address math stays O(1); you pay one extra memory hop to follow the reference. Managed runtimes broadly take this route for arrays of heap objects — the JVM and CPython, for instance, both lay out object arrays as same-size references rather than inlining the objects — while systems languages let you choose between inline values and pointers. The concept is the same everywhere; the default differs. ## The price: fixed capacity Contiguity has a cost. To guarantee that elements 0 through n−1 sit shoulder to shoulder, the block must be reserved as a whole, up front. That is why a static array has a fixed capacity: you cannot extend a block whose neighbouring memory may already belong to something else. Growing means allocating a new, larger block and copying — the machinery of dynamic arrays, which is a separate topic. The static array's deal is simple: give me my size at creation time, and I give you constant-time access to every cell forever. ## What changes at scale — and what doesn't At 10^9 elements the address computation is *exactly* as cheap as at 10 elements — the multiply and add do not grow. What scale changes is the memory budget: `capacity × element_size` is the footprint, so a billion 1-byte samples is about 1 GB while a billion 16-byte records is about 16 GB. The element-size choice, irrelevant to the asymptotic access cost, decides whether the array fits in RAM at all. Interviewers use this to check that you separate *time to reach an element* (constant) from *space to hold them all* (linear in count, scaled by element size). ## What this is not O(1) *indexed access* is not O(1) *search*. The formula takes you to a position, not to a value: finding which index holds a given price is still a linear scan unless the data is organized for searching. Conflating "arrays access in O(1)" with "arrays find in O(1)" is one of the most common junior slips in this area.

  • Does the same trick work outside memory — say, locating record 5,000,000 in a binary file of fixed-width trade ticks?
    Yes. If every record is the same width, record i starts at header + i × record_size, so one seek lands on it. It works for exactly the same reason the in-memory version does: fixed width makes position computable. Variable-width records break it — then you need a scan or a separate offset index.
  • At a billion elements, does anything about indexing get slower?
    The address math does not — it is still one multiply and one add. What changes is the footprint: capacity × element size. A billion 1-byte samples is about 1 GB; a billion 16-byte records is about 16 GB. Element-size choice decides whether the array fits in RAM at all, while the asymptotic access cost stays constant.
  • What if elements are variable-size — can you still index in O(1)?
    Not directly, because element i's position would depend on the sizes of everything before it. The standard fixes are indirection — store fixed-size references to the variable-size data, keeping O(1) plus one extra hop — or a precomputed offset table. With neither, finding element i degenerates to a scan.

Numbered mailboxes of identical width in one long row: to reach box 5,000,000 you never open the first 4,999,999 — you compute exactly where it must stand and walk straight to it.

saying these in an interview costs you the question

  • Confuses O(1) indexed access with O(1) search for a value
  • Believes access gets slower as the index grows larger
  • Cannot state the base + index × element-size formula
  • Thinks elements could be scattered or variable-size with no indirection and still indexed in O(1)

context