
Understanding Linked Lists (DSA Series)
dsa data-structures algorithms
Note (2025) This post is part of a brief CS Fundamentals / DSA series. Linked lists rarely appear in day-to-day Rails/web > work, but they’re still foundational for interviews and for understanding how higher-level containers work under the hood. If you prefer strictly application-engineering topics, feel free to skip—but if you’re brushing > up for interviews or low-level systems work, this will help.
What is a linked list?
A linked list is a linear collection of elements (nodes) where each node holds:
- a value, and
- a reference (link) to the next node (and optionally the previous node).
Unlike arrays, linked lists don’t require contiguous memory; nodes can live anywhere in memory, connected by references.
Flavors
- Singly linked list (SLL): each node points to next.
- Doubly linked list (DLL): each node points to prev and next.
- Circular variants link the tail back to the head.
Why (and when) to use one?
Pros
O(1)
insertion/deletion at head (and tail, if you keep a tail pointer).- No large contiguous memory requirement.
- Stable references to nodes even as the list grows.
Cons
O(n)
random access; you must traverse from head.- Extra memory per node for pointers.
- Worse cache locality than arrays.
Typical uses
- Implementing queues/deques/LRU caches (often DLL + hash map).
- Adjacency lists in graphs.
- Streaming scenarios where you frequently push/pop at ends.
Core Operations (singly linked list)
Below is minimal, language-agnostic pseudocode; adapt easily to Ruby, Python, or JS.
Node
class Node:
value
next
Insert at head — O(1)
def push_front(head, value):
node = Node(value)
node.next = head
return node # new head
Insert after a node — O(1)
def insert_after(node, value):
new_node = Node(value)
new_node.next = node.next
node.next = new_node
Delete after a node — O(1)
def delete_after(node):
if node == null or node.next == null: return
node.next = node.next.next
Search — O(n)
def find(head, target):
cur = head
while cur != null:
if cur.value == target: return cur
cur = cur.next
return null
Doubly Linked List essentials
A DLL node stores prev
and next
:
class Node:
value
prev
next
Benefits
O(1)
delete from the middle when you already hold a node reference (update both neighbors).- Natural fit for LRU and deque operations.
Trade-off
- Slightly more memory and pointer bookkeeping.
Complexity & Trade-offs
Operation | SLL | DLL | Array (dynamic) |
---|---|---|---|
Access k-th element | O(n) | O(n) | O(1) |
Insert at head | O(1) | O(1) | O(n) (shift) |
Insert at tail (with tail ptr) | O(1) | O(1) | Amortized O(1) |
Delete given a node ref | O(1) | O(1) | O(n) (shift) |
Memory overhead per element | pointer | 2 pointers | none extra |
Cache friendliness | lower | lower | higher |
Rule of thumb: If you need frequent insertions/removals at the ends or you maintain node references, lists shine. For random access by index, arrays win.
When not to use a linked list
- You need frequent k-th element access by index.
- Your dataset is small and simpler array methods suffice.
- You depend heavily on CPU cache locality for performance.
Modern libraries often give you the right structure already (e.g., Deque
, LinkedList
, OrderedDict
in various languages), implemented efficiently and tested—use them first.
In the real world (2025)
- Application code (Rails, web APIs) seldom needs hand-rolled lists—built-in containers are faster and safer.
- Interviews still ask list problems (reverse a list, detect cycles, merge k lists).
- Systems work (caches, schedulers, memory allocators) still relies on list-like structures behind the scenes.
Practice prompts
- Reverse a singly linked list (iterative & recursive).
- Detect a cycle (Floyd’s tortoise–hare).
- Delete a node in O(1) given only that node (SLL trick: copy next’s value, bypass next).
- Merge two sorted lists.
- Implement an LRU cache (DLL + hash map).
Wrap-up
Linked lists are a conceptual cornerstone. Even if you rarely write one from scratch in production, understanding their costs and benefits helps you pick the right container—and ace common interview tasks.