Array
A fixed-size block of contiguous memory holding elements of one type, addressable by index in O(1).
Definition
An array stores n elements of the same type in one contiguous block of memory. Element i lives at address base + i * elementSize, so reading or writing any index is a single multiply-add and a memory load — O(1) regardless of n.
A static array has a fixed capacity chosen at creation. Growing it means allocating a new block and copying, which is exactly what a Dynamic Array automates. Nearly every other structure — String, Matrix (2D Array), Hash Table, Binary Heap, Adjacency Matrix — is ultimately built on arrays.
Arrays are the default container in interviews. Most "array problems" are not about the structure itself but about the algorithms that exploit index arithmetic: Binary Search, Two Pointers (Opposite Ends), Sliding Window (Variable Size), Prefix Sum, and in-place partitioning.
Intuition
A mental model before the formal terms.
Picture a row of numbered mailboxes bolted to a wall. Because every box is the same size and they sit side by side, the postal worker does not search for box 37 — they walk exactly 37 box-widths from the start. That is why indexed access is constant time.
The same physical layout is the weakness: inserting a new mailbox in the middle means unbolting and shifting every box after it one slot to the right. Deleting from the middle shifts them back. Only the end of the row is cheap to change.
How it works
- Allocation reserves
capacity * elementSizebytes and remembers the base address. get(i)andset(i, v)computebase + i * elementSizeand read/write that word. Bounds are checked in most languages (0 <= i < n).insertAt(i, v)shifts elementsi..n-1one position right (n - imoves), then writesvati. Requiresn < capacity.deleteAt(i)shifts elementsi+1..n-1one position left and decrementsn.search(v)with no ordering information scans every element (Linear Search); if the array is sorted, Binary Search finds it inO(log n).
Why it works
Constant-time access follows directly from the address formula: the position of element i is a pure function of i, with no pointers to follow.
Contiguity also makes arrays cache-friendly: a sequential scan pulls 8–16 neighbouring elements into cache per line, so iterating an array of one million ints is often 10× faster than walking a Linked List of the same size even though both are "O(n)".
Shifting on insert/delete is unavoidable because the address formula assumes no gaps: element i+1 must sit exactly one slot after element i.
Operations
| Operation | Description | Cost |
|---|---|---|
| get(i) | Read the element at index i via base + i * size. | O(1) |
| set(i, v) | Overwrite the element at index i. | O(1) |
| search(v) | Scan for value v; O(log n) with binary search if sorted. | O(n) |
| insertAt(i, v) | Shift a[i..n-1] right by one and write v; needs spare capacity. | O(n) |
| deleteAt(i) | Shift a[i+1..n-1] left by one. | O(n) |
| append(v) | Write at index n if n < capacity; otherwise the array is full. | O(1) |
| traverse | Visit every element in index order; sequential memory access is cache-friendly. | O(n) |
Recognition
How to tell a problem wants this.
- The input is given as a list/sequence of numbers or characters and you need indexed access (
a[i],a[i-1],a[mid]). - The problem asks for subarrays, contiguous ranges, "in-place" modification, or
O(1)extra space — all rely on index arithmetic. - Sorted input, or "you may sort first", signals Binary Search or Two Pointers (Opposite Ends) over an array.
Interactive demo
Play, step, change the input. ← → and space work too.
Showing the closely related Linear Search visualization.
1for i in 0 .. n-1:2 if a[i] == target: return i3return -1Pseudocode
1class Array(capacity):2 data = allocate(capacity); n = 03 get(i): assert 0 <= i < n; return data[i]4 set(i, v): assert 0 <= i < n; data[i] = v5 insertAt(i, v):6 assert n < capacity and 0 <= i <= n7 for j = n down to i+1: data[j] = data[j-1]8 data[i] = v; n += 19 deleteAt(i):10 for j = i to n-2: data[j] = data[j+1]11 n -= 112 search(v): for i in 0..n-1: if data[i] == v return i; return -1Implementation
1from typing import Generic, TypeVar2 3T = TypeVar("T")4 5 6class StaticArray(Generic[T]):7 """Fixed-capacity array with explicit shifting on insert/delete."""8 91 · Storage and size10 def __init__(self, capacity: int) -> None:11 self._data: list[T | None] = [None] * capacity # allocated once12 self._n = 0 # live elements13 self._capacity = capacity14 15 def __len__(self) -> int:16 return self._n17 182 · Bounds-checked access19 def get(self, i: int) -> T:20 if not 0 <= i < self._n:21 raise IndexError(i)22 return self._data[i] # type: ignore[return-value]23 24 def set(self, i: int, value: T) -> None:25 if not 0 <= i < self._n:26 raise IndexError(i)27 self._data[i] = value28 293 · Insert with right shift30 def insert_at(self, i: int, value: T) -> None:31 if self._n == self._capacity:32 raise OverflowError("array is full")33 if not 0 <= i <= self._n:34 raise IndexError(i)35 for j in range(self._n, i, -1):36 self._data[j] = self._data[j - 1]37 self._data[i] = value38 self._n += 139 40 def append(self, value: T) -> None:41 self.insert_at(self._n, value)42 434 · Delete with left shift44 def delete_at(self, i: int) -> T:45 if not 0 <= i < self._n:46 raise IndexError(i)47 removed = self._data[i]48 for j in range(i, self._n - 1):49 self._data[j] = self._data[j + 1]50 self._n -= 151 self._data[self._n] = None52 return removed # type: ignore[return-value]53 545 · Linear search55 def search(self, value: T) -> int:56 for i in range(self._n):57 if self._data[i] == value:58 return i59 return -1[None] * capacityallocates the fixed block;_ncounts live elements.__len__makeslen(arr)work, following the sequence protocol.insert_atshifts right withrange(self._n, i, -1), then stores the value and bumps_n.delete_atshifts left and clears the trailing slot so the object can be collected.searchis whatlist.indexdoes internally, except it returns-1instead of raisingValueError.
A Python list of ints stores pointers to boxed objects, so it is far less cache-friendly than a C array; use array.array or NumPy for dense numeric data.
- Python has no fixed-size array in the core language;
listis a dynamic array.array.array("i")and NumPy arrays are the compact fixed-type options. list.insert(i, v)anddel lst[i]do the same O(n) shifting in C.- Negative indices wrap around (
lst[-1]), which hand-rolled structures should explicitly reject or support.
- Building a 2-D grid with
[[0] * n] * m— every row is the same list object. - Using
lst.index(v)without catchingValueErrorwhen the value may be absent. - Assuming
lst.insert(0, v)is O(1) — it shifts every element.
- Only C++ has a true fixed-size array (
int[N],std::array); JS/TS arrays and Python lists are dynamic, so the "static" class is a teaching device there. - Out-of-range access: C++
operator[]is undefined behaviour, JS returnsundefined, Python raisesIndexError(and negative indices wrap). - Element storage: C++ arrays hold values contiguously; Python lists hold pointers to boxed objects; JS engines pick packed/holey representations dynamically.
- Typed arrays (
Int32Array) in JS/TS andarray.array/NumPy in Python approximate C-style dense numeric arrays.
Complexity
| Operation | Average | Worst | Note |
|---|---|---|---|
| Access | O(1) | O(1) | |
| Search | O(n) | O(n) | O(log n) if sorted, via binary search. |
| Insert | O(n) | O(n) | O(1) at the end when capacity remains. |
| Delete | O(n) | O(n) | O(1) at the end. |
| Update | O(1) | O(1) | |
| Traverse | O(n) | O(n) | |
| Resize | O(n) | O(n) | Allocate a new block and copy. |
| Space | O(n) | Space is the full capacity, even when partially filled. | |
Advantages & disadvantages
O(1)random access to any index — the basis of binary search, heaps and hash tables.- Best possible memory locality: contiguous storage means fast scans and low per-element overhead (no pointers).
- Simple to reason about; supported natively in every language.
- Fixed capacity: growing requires a fresh allocation and an
O(n)copy. - Insert or delete anywhere except the end costs
O(n)shifting. - Unordered search is
O(n); you need sorting or a Hash Map for faster lookups. - All elements must be the same size/type (in typed languages) and the block must be allocated contiguously, which can fail for very large
non fragmented heaps.
Use cases
- Backing store for Dynamic Array, String, Matrix (2D Array), Binary Heap, Hash Table buckets and Adjacency Matrix.
- Lookup tables indexed by a small integer key (counts of 26 letters, DP tables, sieve of primes).
- Fixed-size buffers: audio frames, pixel rows, network packets.
- Any problem solved by index arithmetic: prefix sums, two pointers, sliding windows, in-place partitioning.
- You know the size up front, or it never changes (DP tables, frequency counts over a fixed alphabet).
- You need
O(1)random access by integer index. - Throughput matters: scans, sorts and binary searches over arrays benefit from cache locality.
- Frequent inserts or deletes in the middle — each is
O(n); consider a Linked List (with a pointer already in hand) or a balanced tree. - Unknown or highly variable size — use a Dynamic Array to avoid manual reallocation.
- Lookups by non-integer key or sparse integer keys (e.g. user IDs up to 10^9) — use a Hash Map.
Alternatives
Common mistakes
- Off-by-one on bounds: iterating to
ninstead ofn - 1, orinsertAt(n)treated as invalid when it is the legal append position. - Forgetting that in-place insert/delete shifts indices of later elements — iterating forward while deleting skips elements.
- Assuming
O(1)insertion in the middle because the language hides the shifting (list.insert,splice). - Using
(lo + hi) / 2for a midpoint in fixed-width languages; it overflows near2^31. - Confusing the array length with its capacity in languages that expose both.
Interview patterns
- Two pointers from both ends on a sorted array (two-sum II, container with most water).
- Overwrite in place with a slow/fast write pointer (remove duplicates, move zeroes).
- Use the array itself as a hash by index (find duplicate via cycle, missing number by negation).
- Prefix sums for
O(1)range sums afterO(n)preprocessing. - Cyclic rotation via three reversals in
O(n)time andO(1)space.
- Recognizing the approach from an array and a targetIntermediate
- Deciding whether O(n²) can be improvedIntermediate
- Hash map or array?Beginner
- Where does O(n log n) come from?Beginner
- Minimum Size Subarray SumIntermediate
- Two SumBeginner
- Longest Substring Without Repeating CharactersIntermediate