Contiguous vs. Linked Data Structures

Every data structure is built on one of two physical foundations: a contiguous block of memory (arrays) or chunks of memory connected by pointers (linked structures). Everything else — stacks, queues, trees, hash tables — is built on top of one of these two ideas.

The choice matters more than it might seem at first. The same logical operation (say, deleting an element) can be trivial on one and expensive on the other.


Arrays

An array is a fixed sequence of elements stored in a single, unbroken block of memory. Each element sits at a predictable offset from the start, so the CPU can jump directly to any position given its index.

A useful mental model: think of an array as a row of numbered post office boxes. You know exactly where box 47 is without having to check any of the others first.

Searching an Array

Unsorted array: You have no choice but to check each element one by one until you find a match — or run out of elements. This is O(n) in the worst case.

Sorted array: You can use binary search. Start at the middle, and depending on whether your target is higher or lower, discard half the remaining elements and repeat. This gives O(log n) — a dramatic improvement for large arrays.

def binary_search(arr, target):
    low, high = 0, len(arr) - 1
    while low <= high:
        mid = (low + high) // 2
        if arr[mid] == target:
            return mid
        elif arr[mid] < target:
            low = mid + 1
        else:
            high = mid - 1
    return -1

Binary search is only possible because arrays give you random access — you can jump to the middle element in O(1). A linked list cannot do this.


Pointers and Linked Structures

A linked list stores each element in its own separate node. Each node holds the data and a pointer to the next node. There is no requirement that nodes sit next to each other in memory — they are scattered wherever the allocator found space, and the pointers stitch them together.

Singly and doubly linked list diagrams
circle-check
circle-info

This will make a bit more sense with dictionaries in mind.

The two common variants are:

  • Singly linked: each node points only to its successor.

  • Doubly linked: each node points to both its successor and its predecessor. This costs one extra pointer per node but makes several operations significantly cheaper.

Searching a Linked List

There is no shortcut here. Regardless of whether the list is sorted, you must start at the head and follow pointers until you find the target or reach the end. This is O(n) always.

Sorting a linked list does offer one minor benefit: if you pass the value you're looking for, you can stop early. But the worst case remains O(n).

Binary search is not possible on a linked list. To reach the middle element you would have to traverse half the list first, which defeats the purpose entirely.


Comparison

Today's computers have gigabytes of RAM, so the extra memory used by pointer fields in a linked list is rarely a concern in practice. What matters more is time — specifically, how the choice of structure affects the operations your program performs most often.

Operation
Unsorted Array
Sorted Array
Singly Linked
Doubly Linked

Search

O(n)

O(log n)

O(n)

O(n)

Append

O(1)*

O(n)

O(1)**

O(1)**

Insert at position

O(n)

O(n)

O(1)***

O(1)***

Delete

O(1)*

O(n)

O(n)

O(1)

Access by index

O(1)

O(1)

O(n)

O(n)

* Amortised for dynamic arrays; requires the swap trick for deletion. ** Requires a tail pointer. *** Given a pointer to the insertion point; finding that point is O(n).

circle-info

The right question is never "which structure is faster?" but rather "which operations does my program perform most, and which structure makes those cheapest?" A structure that excels at search may be poor at insertion, and vice versa.

Last updated