Nodes and pointers
A linked list stores each element in its own node, and each node holds a pointer to the next one. The nodes can sit anywhere in memory; the pointers chain them together. The list itself only remembers the first node, the head.
That changes the costs compared with an array. Getting to element *n* means following n pointers: O(n), no jumping by index. But if you already hold a node, inserting or removing right after it is O(1): repoint two pointers, nothing moves. A doubly linked list adds a pointer back to the previous node, so you can also remove the node you're holding and walk in both directions.
A music playlist where songs are constantly inserted after the current one and removed while playing. Inside operating systems, lists of processes and free memory blocks are classic linked lists.
In code: Python · Rust
class Node:
def __init__(self, value, next=None):
self.value, self.next = value, next
head = Node("A", Node("B", Node("C")))
b = head.next
b.next = Node("X", b.next) # insert after B: O(1)
# For a real queue or deque, use collections.deque insteaduse std::collections::LinkedList; // doubly linked
let mut l: LinkedList<&str> = LinkedList::new();
l.push_back("B");
l.push_front("A"); // O(1) at both ends
// Hand-written linked lists are famously awkward in Rust
// because each node has one owner; VecDeque is usually the better choice.- In everyday Python and Rust code you rarely write a linked list yourself: deque and VecDeque cover most uses and are faster.
- Linked lists still matter in interviews and inside systems: LRU caches, allocators, the Linux kernel's lists.