Skip to content

What Is an Array? Contiguous Memory, O(1) Access, and Every Common Operation (Python + TypeScript)

Published: at 09:00 AM

Arrays are the first data structure everyone meets and the one most people never look at closely again. That’s a shame, because almost every structure you’ll learn later (strings, stacks, hash tables, even the guts of a vector database) is built on top of the humble array. This post is the written, go-deeper companion to my 60-second visual explainer:

If you prefer moving pictures, watch it on YouTube and subscribe to @onurthedev — I turn one CS concept into a visual short every week, and each one gets a deep-dive post like this here.

Table of contents

Open Table of contents

The one-sentence definition

An array is a contiguous block of memory holding elements of the same size, where each element is identified by its index.

Two words in that sentence do all the work: contiguous and index.

Why contiguous memory is the whole trick

When you create an array, the runtime reserves one unbroken run of bytes. If an array of 32-bit integers starts at memory address 1000, the layout is:

index:      0       1       2       3       4
address:  1000    1004    1008    1012    1016
value:     42      7       19      3       88

That layout means the computer never searches for an element. It computes where the element must be:

address_of(i) = base_address + i * element_size
address_of(3) = 1000 + 3 * 4 = 1012

One multiplication, one addition, done. It does not matter if the array has ten elements or ten million: fetching arr[3] costs the same. That’s what we mean when we say array access is O(1), constant time. (That formula is also the real reason indexes start at 0, which is the topic of the next post in this series.)

What Python and TypeScript actually give you

Neither language hands you a raw fixed-size C array by default, and it’s worth knowing what you’re really holding:

The mental model of “contiguous slots, indexed from 0” still holds for all of them, and so do the complexities below.

The common operations, with code

Here is the cheat sheet, then the code:

OperationComplexityWhy
Access by indexO(1)address arithmetic, no searching
Update by indexO(1)same arithmetic, then overwrite
Search (unsorted)O(n)might have to look at every element
Insert at endO(1) amortizedusually free space; occasional resize is O(n)
Insert at indexO(n)everything after it must shift right
Delete at endO(1)nothing shifts
Delete at indexO(n)everything after it must shift left
TraverseO(n)touch each element once

Access and update: O(1)

scores = [42, 7, 19, 3, 88]

third = scores[2]      # 19 — one arithmetic step, regardless of length
scores[2] = 100        # update is the same arithmetic plus a write
last = scores[-1]      # 88 — Python nicety: negative indexes count from the end
const scores: number[] = [42, 7, 19, 3, 88];

const third = scores[2];       // 19
scores[2] = 100;               // O(1) update
const last = scores.at(-1);    // 88 — .at() gives you negative indexing in TS/JS

Search: O(n)

In an unsorted array there is no shortcut. You check elements one by one, and on average you’ll check half of them:

def find_index(items: list[int], target: int) -> int:
    for i, value in enumerate(items):
        if value == target:
            return i
    return -1

find_index(scores, 3)   # 3
3 in scores             # True — same O(n) scan, nicer syntax
function findIndex(items: number[], target: number): number {
  for (let i = 0; i < items.length; i++) {
    if (items[i] === target) return i;
  }
  return -1;
}

scores.indexOf(3);       // 3 — built-in, still O(n)
scores.includes(3);      // true

If the array is sorted, binary search drops this to O(log n). That’s a future episode; the point for now is that sortedness is a property you pay for elsewhere to make search cheap.

Insert: O(1) at the end, O(n) anywhere else

Appending is cheap because dynamic arrays keep spare capacity at the end. Inserting in the middle is expensive because contiguity is non-negotiable: to put something at index 1, every element from index 1 onward has to move one slot right.

scores.append(55)        # O(1) amortized
scores.insert(1, 99)     # O(n) — shifts everything after index 1
scores.push(55);         // O(1) amortized
scores.splice(1, 0, 99); // O(n) — same shifting cost, sneakier syntax

The word amortized hides a nice mechanism: when the reserved block fills up, the runtime allocates a bigger block (typically ~1.5 to 2x) and copies everything over. That one append costs O(n), but it buys so much free space that the average append stays O(1). You get this for free; it’s still worth knowing it happens.

Delete: mirror image of insert

scores.pop()             # O(1) — remove last
scores.pop(1)            # O(n) — remove index 1, shift everything left
scores.remove(88)        # O(n) — search for the value, then shift
scores.pop();            // O(1)
scores.splice(1, 1);     // O(n)

A classic interview-grade trick: if order doesn’t matter, delete from the middle in O(1) by swapping the victim with the last element and popping.

def swap_remove(items: list, i: int) -> None:
    items[i] = items[-1]
    items.pop()

Traverse: O(n)

for score in scores:
    print(score)

total = sum(scores)
doubled = [s * 2 for s in scores]
for (const score of scores) {
  console.log(score);
}

const total = scores.reduce((acc, s) => acc + s, 0);
const doubled = scores.map(s => s * 2);

There is a lot more to say about iteration (index-based vs value-based loops, off-by-one traps, when for...in betrays you in JavaScript). I cover all of it in the follow-up post.

When an array is the right tool

Reach for an array when you read by position a lot, iterate over everything, or mostly add/remove at the end. Think hard before using one when you insert/delete in the middle constantly (a linked list or a different design may fit) or when you mostly look things up by a key rather than a position (that’s a hash map’s job). Those structures are coming up in this series, and every one of them will be easier to understand because you now know exactly what an array does and what it costs.

Keep going