Linked List Visualization — Step by Step
Linear data structure where each node points to the next. Supports insert, delete, and search with traversal.
// quick answer
Linked List is a data structures structure that runs in O(n) time on average with O(n) space. Linear data structure where each node points to the next. Supports insert, delete, and search with traversal.
How Linked List Works
A Linked List is a sequence of nodes where each node contains data and a pointer to the next node. Unlike arrays, insertion and deletion at any position is O(1) if you have a reference to the node, but accessing by index requires O(n) traversal.
Linked List Step by Step
Anatomy of a node
A linked list is a chain of nodes, each holding two things: a value and a next pointer to the following node. The list itself is just a single head pointer to the first node; the last node's next is null, marking the end. That is the whole structure. Unlike an array, the nodes are *not* contiguous in memory — each one lives wherever the allocator put it, and only the pointers hold the sequence together. This is the source of every linked-list strength (cheap local restructuring) and every weakness (no jumping to position i, poor cache behavior).
Traversal: follow the pointers
The only way to reach a node is to walk to it: start at head, follow next, repeat until you hit null. To find the value 42 in 10 → 42 → 7, you compare 10 (no), follow the pointer, compare 42 (found) — the visualizer highlights each node as the search walks past it. This is why access and search are O(n): reaching the k-th node costs k pointer hops, and there is no shortcut. Contrast an array, where a[k] is one multiply-and-add away. A linked list trades indexed access for flexible structure.
Insertion: rewiring, not shifting
Inserting at the head is two pointer writes: point the new node's next at the current head, then point head at the new node — O(1) no matter how long the list is. Inserting after any node you already hold a reference to is equally cheap: newNode.next = node.next; node.next = newNode. Compare an array, where inserting at the front shifts every element right. The catch is the word *already*: inserting at the tail or at index i first requires an O(n) walk to get there (unless you also maintain a tail pointer). The demo above builds the list by inserting each value at the tail.
Deletion needs the previous node
To delete a node you splice it out: prev.next = curr.next, and the chain simply flows around it. The subtlety is that in a singly linked list you cannot get from a node back to its predecessor, so deletion means walking with two pointers — prev trailing one step behind curr — until curr holds the target. Deleting the head is the special case with no predecessor: just advance head. The visualizer demo shows this exact dance: it searches for the middle value, then deletes it, and you can watch the neighboring pointer being rewired.
Reversing a linked list
The classic interview exercise is pure pointer choreography. Walk the list with three pointers — prev (starts null), curr (starts at head), and next — and at each node: save next = curr.next, flip the arrow with curr.next = prev, then advance prev = curr; curr = next. Trace it on 1 → 2 → 3: after step one the 1-node points at null; after step two, 2 points at 1; after step three, 3 points at 2, and prev is the new head of 3 → 2 → 1. One pass, O(n) time, O(1) extra space, every arrow reversed in place.
Linked lists vs arrays in practice
On paper linked lists win at insertion and deletion; in practice arrays usually win overall. Array elements sit side by side, so the CPU cache loads many at once, while chasing list pointers scatters across memory and stalls on every hop — a linear scan over an array is often 10–100× faster than over an equivalent list. Each node also pays pointer and allocation overhead per element. Where lists genuinely earn their keep: splicing with a node reference in hand (LRU caches), hash table collision chains, and adjacency lists — plus stacks and queues can be built on them when arrays are awkward.
Time & Space Complexity
| Best Case | Average Case | Worst Case | Space |
|---|---|---|---|
| O(1) | O(n) | O(n) | O(n) |
Linked List Pseudocode
Linked List operations:
insertHead(value):
new node → head
insertTail(value):
traverse to end, append
delete(value):
find node, rewire pointers
search(value):
traverse until foundPress play in the visualizer above to watch each line execute with live highlighting.
Linked ListCode in JavaScript, Python & Java
JavaScript
class ListNode {
constructor(value, next = null) {
this.value = value;
this.next = next;
}
}
class LinkedList {
head = null;
insertHead(value) {
this.head = new ListNode(value, this.head);
}
find(value) {
let node = this.head;
while (node !== null && node.value !== value) node = node.next;
return node; // null if not found
}
delete(value) {
if (this.head === null) return false;
if (this.head.value === value) {
this.head = this.head.next;
return true;
}
let prev = this.head;
while (prev.next !== null && prev.next.value !== value) prev = prev.next;
if (prev.next === null) return false;
prev.next = prev.next.next;
return true;
}
}Python
class Node:
def __init__(self, value, next=None):
self.value = value
self.next = next
class LinkedList:
def __init__(self):
self.head = None
def insert_head(self, value):
self.head = Node(value, self.head)
def find(self, value):
node = self.head
while node and node.value != value:
node = node.next
return node # None if not found
def delete(self, value):
if not self.head:
return False
if self.head.value == value:
self.head = self.head.next
return True
prev = self.head
while prev.next and prev.next.value != value:
prev = prev.next
if not prev.next:
return False
prev.next = prev.next.next
return TrueJava
public class LinkedList {
private static class Node {
int value;
Node next;
Node(int value, Node next) { this.value = value; this.next = next; }
}
private Node head;
public void insertHead(int value) {
head = new Node(value, head);
}
public boolean contains(int value) {
for (Node n = head; n != null; n = n.next) {
if (n.value == value) return true;
}
return false;
}
public boolean delete(int value) {
if (head == null) return false;
if (head.value == value) { head = head.next; return true; }
Node prev = head;
while (prev.next != null && prev.next.value != value) prev = prev.next;
if (prev.next == null) return false;
prev.next = prev.next.next;
return true;
}
}When to Use Linked List
- O(1) insert/delete when you already hold a reference to the neighboring node — the core of LRU caches (hash map pointing into a doubly linked list), free lists in allocators, and schedulers.
- As internal plumbing for other structures: hash table collision chains, graph adjacency lists, and linked implementations of stacks and queues.
- Frequent splicing — concatenating two lists, or removing a run of consecutive nodes — is O(1) pointer surgery, versus O(n) copying for arrays.
- Not for indexed or random access: reaching position i costs O(n) hops. If you ever write
list.get(i)in a loop, you want an array. - Rarely the default choice in modern code: pointer chasing is cache-hostile and each node carries allocation overhead, so dynamic arrays (JavaScript arrays, Python lists, Java ArrayList) beat linked lists in most real workloads — measure before choosing one.
- Learn them anyway: pointer manipulation (reverse a list, detect a cycle, merge sorted lists) is a staple of interviews and the mental model behind trees and graphs.
Linked List — Frequently Asked Questions
Linked list vs array — which is faster?
Arrays, in most real situations. Array elements are contiguous, so indexed access is O(1) and scans are cache-friendly, while a linked list must hop pointer to pointer, costing O(n) to reach a position and stalling the CPU cache on every hop. Linked lists only win when you repeatedly insert or delete at a position you already hold a node reference to, avoiding the array's O(n) shifting.
What is a linked list actually used for?
Mostly as internal machinery. LRU caches pair a hash map with a doubly linked list so any entry can be moved to the front in O(1). Hash tables use short linked chains to handle collisions. Memory allocators track free blocks in linked free lists, and graph adjacency lists are often linked. Directly, application code tends to reach for dynamic arrays instead.
How do you reverse a linked list?
Walk the list once with three pointers: prev starting at null, curr at the head, and next saving where to go. At each node, store next, point curr.next back at prev, then advance both prev and curr. When curr reaches null, prev is the new head. This runs in O(n) time and O(1) extra space and is the single most common linked-list interview question.
What is the difference between singly and doubly linked lists?
A singly linked node stores one pointer, next; a doubly linked node also stores prev, pointing backward. The extra pointer lets you traverse in both directions and delete a node in O(1) given only that node, since its predecessor is reachable directly. The costs are one extra pointer of memory per node and more pointer updates to keep consistent on every insert and delete.
Why is accessing a linked list element O(n) when arrays are O(1)?
An array computes an element's memory address directly from its index, because all elements sit in one contiguous block at fixed intervals — one arithmetic step regardless of size. Linked list nodes are scattered across memory, connected only by pointers, so the address of node k is unknowable until you have followed k pointers from the head. The structure has no index; it only has a path.
Related Algorithms
- Stack (LIFO) Visualization — Last In, First Out data structure. Push adds to the top, pop removes from the top.
- Queue (FIFO) Visualization — First In, First Out data structure. Enqueue adds to the rear, dequeue removes from the front.
References & Further Reading
- Wikipedia — Linked list
- Cormen, Leiserson, Rivest & Stein — Introduction to Algorithms (4th ed., MIT Press)