Module F-2·16 min read

Why array indexing is O(1), insertion/deletion costs, and the array-based patterns — reversal, flattening, subarrays — you'll reuse everywhere.

JJS
Written by Jatin Jain Saraf · Senior Software Engineer

Module F-2 — Arrays: Memory and Access Patterns

What this module covers: Arrays are the first data structure everyone learns and the last one most engineers actually understand at the memory level. This module covers why array indexing is O(1), why insertion and deletion aren't the same cost everywhere in the array, how JavaScript engines grow arrays under the hood, and the reversal/subarray/flattening patterns that show up in almost every other module in this course.


Why Indexing Is O(1)

An array is a block of memory where every element sits the same distance apart, one after another. If you know the address where the array starts, and you know how large each element is, you can compute the address of any element with one multiplication and one addition:

address_of(arr[i]) = base_address + (i × element_size)

No searching. No walking through the structure. The engine computes an address and reads directly from it. That's why arr[500000] and arr[0] cost exactly the same — one arithmetic operation, regardless of array size. This is what O(1) access actually means at the hardware level, and it's the reason arrays are the default choice whenever you need to read by position.

Analogy: An array is an apartment building with a fixed unit size. If you know the building's street address and that each floor is identical, you can walk straight to apartment 47 without checking apartments 1 through 46 first. A linked list (Module P-2) is the opposite — you have to walk through every unit in order, because unit 47 doesn't tell you where it is until unit 46 hands you directions to it.

Why this matters in production: this is exactly why users[userId]-style lookups by numeric position are cheap, and why reaching for an array when you actually need to look things up by an arbitrary key (an email, a UUID) is the wrong structure — that's what Module F-4 (Hash Maps) is for. Arrays are fast at "give me position N." They are not fast at "find me the thing with this ID," because that requires scanning.


Insertion and Deletion: It Depends Where

Reading is uniformly O(1). Writing is not — the cost depends entirely on where in the array you insert or remove.

typescript

push/pop at the end don't disturb any other element — the array's shape after the operation just has one more or one fewer slot at the tail. unshift/shift/splice in the middle or at the front require physically moving every subsequent element to close or open a gap, because the whole point of an array is that elements stay contiguous and evenly spaced. Insert at the front of a 100,000-element array and you move 100,000 elements to make room for one.

This is the single most common array performance mistake: reaching for unshift() in a hot path (a queue implemented as array.push() + array.shift(), for instance) without realizing that the "removal" half of that pattern is O(n), not O(1). Module F-7 (Queues) covers the structure that actually gives you O(1) on both ends.


How Dynamic Arrays Actually Grow

JavaScript arrays (and Python lists, and Java's ArrayList) look like they can grow forever with no cost, because push() never asks you to declare a size upfront. Under the hood, engines allocate a fixed-size backing buffer and grow it by over-allocating — when the buffer is full, the engine allocates a new, larger buffer (commonly double the size) and copies every existing element into it.

typescript

Sign in to keep reading

The rest of this module is free — sign in with Google to unlock it and track your progress.

Sign in & Register

Discussion

0

Join the discussion

Loading comments...

© 2026 Jatin Jain Saraf (JJS). All rights reserved.