Skip to content
Forge Learn/Linked Lists

Singly Linked Lists

6 min read

You'll learn to

  • -Explain how a singly linked list chains Node objects together via next references
  • -Compare linked list insertion to array/list insertion in Big-O terms
  • -Recognize the core tradeoff: O(1) head insertion versus no random access

Every structure built so far this tier - the stack, the circular-buffer queue, the hashmap's buckets - leaned on a Python list, a contiguous array under the hood. A linked list throws that away entirely and builds a chain of separate objects instead, trading random access for genuinely cheap insertion and removal at the ends.

The Node: value + next

The building block of a linked list - one value, one pointer to the next node

A linked list is nothing more than a chain of these Node objects - each one points to the next, and the list itself only needs to remember where the chain starts (head) and, usually, where it ends (tail).

A minimal LinkedList with head/tail-tracked prepend and append

Why Head Insertion is O(1) Here but O(n) for a Python List

Inserting at the front of a Python list with list.insert(0, x) forces every existing element to shift one slot to the right - O(n), the exact same shifting cost as the naive queue's pop(0) from the previous module. A linked list's prepend touches only one new node and the existing head reference - two pointer assignments, full stop, regardless of how long the chain already is. That is O(1), always, no matter the list's current size.

The Tradeoff: No Random Access

The cost of that flexibility is that a linked list cannot jump directly to "the 500th element" the way arr[500] does on a Python list. Reaching any node other than the head (or the tail, if tracked) means walking the chain one next reference at a time from the head - an O(n) operation, even though the equivalent lookup on a Python list is O(1).

Operation comparison
O(1)
Insert at front - LinkedList
O(n)
Insert at front - Python list
O(n)
Access by index - LinkedList
O(1)
Access by index - Python list

This is exactly why ordinary code defaults to a Python list, reserving a hand-built linked list for specific situations - implementing another structure's internals (a queue, a stack, an LRU cache's eviction order in the tier's capstone), or anywhere O(1) insertion and removal at both ends is required without ever needing random access.

ScaleDojo Logo
Initializing ScaleDojo