What a linked list is
3 → 7 → 1 → 9 — but the user constantly inserts a song in the middle and removes ones they're bored of. In an array, every insert or delete near the front forces every later song to shift over (O(n)), all day long.val) and a pointer to the next node (next). The figure below shows that chain — each node points to the one after it, and the last points at null (the end).next until you hit null. Because nodes aren't glued into one block, inserting between 3 and 7 just rewires two pointers — nothing shifts. The price: no jumping to "position 5" — you must walk there from the head.Quick check
Reaching the 5th node of a linked list requires…
Answer it in the interactive lesson to keep your progress.
A node, and how you build a chain
val (the value it holds) and next (a pointer to the following node). There is no array and no index; there are only nodes pointing at each other.new ListNode(value) and link two nodes by setting .next. The very last node's .next stays null — that's how you know the chain has ended.Build 1 → 2 → 3
const a = new ListNode(1); // each node holds a value...
const b = new ListNode(2);
const c = new ListNode(3);
a.next = b; // ...and a link to the next node
b.next = c; // the chain is now 1 -> 2 -> 3
console.log(a.val, a.next.val, a.next.next.val); // 1 2 3
console.log(c.next); // null (c is the tail)Quick check
A node in a singly linked list holds…
Answer it in the interactive lesson to keep your progress.
Traverse: walk the whole list
.next from node to node until you fall off the end (null). This one move — while (curr) { …; curr = curr.next } — is the backbone of almost every list algorithm.The steps
- Point a
currmarker at the head. - While
currisn'tnull, do something withcurr.val. - Step forward with
curr = curr.next. - When
currbecomesnull, every node has been visited.
curr pointer march down the chain and drop off the end:This section has a step-by-step animation in the interactive lesson.
function printVals(head) {
const out = [];
let curr = head; // start at the head
while (curr) { // stop once we step past the tail (null)
out.push(curr.val); // read this node's value
curr = curr.next; // follow the pointer to the next node
}
return out;
}
console.log(printVals(buildList([3, 7, 1, 9]))); // [3,7,1,9]Quick check
The walk `while (curr) { curr = curr.next }` stops when…
Answer it in the interactive lesson to keep your progress.
Find a value
The steps
- Walk from the head with a position counter
i. - At each node, check
curr.val === target; if it matches, returni. - Otherwise step forward and add one to
i. - If the walk ends, the value isn't in the list — return
-1.
Trace it — find 1 in 3 → 7 → 1 → 9
- node
3— not1, step on - node
7— not1, step on - node
1— match! return position2
curr marker stops at every node to ask the question — there is no skipping ahead. Before each hop, predict whether it will match or step on.This section has a step-by-step animation in the interactive lesson.
function indexOfVal(head, target) {
let i = 0, curr = head;
while (curr) {
if (curr.val === target) return i; // found it → its position
i++;
curr = curr.next;
}
return -1; // walked off the end → not here
}
const nums = buildList([3, 7, 1, 9]);
console.log(indexOfVal(nums, 1)); // 2
console.log(indexOfVal(nums, 8)); // -1Quick check
Predict: finding 9 (the LAST value) in 3 → 7 → 1 → 9 takes how many value checks?
Answer it in the interactive lesson to keep your progress.
Insert at the head
.next at the current head, and declare the new node the head. Two pointer writes, no matter how long the list is: O(1). (An array would have to slide every element over.)The steps
- Make the new node:
node = new ListNode(val). - Point it at the current head:
node.next = head. - The new node is now the head — return it.
3 slot in front of 7 without a single existing node moving:This section has a step-by-step animation in the interactive lesson.
function insertHead(head, val) {
const node = new ListNode(val); // the new front node
node.next = head; // point it at the old head
return node; // it becomes the new head
}
let h5 = buildList([7, 1, 9]);
h5 = insertHead(h5, 3); // prepend 3
console.log(printVals(h5)); // [3,7,1,9]Quick check
Inserting 3 at the head of 7 → 1: predict what breaks if you set head = node BEFORE node.next = head.
Answer it in the interactive lesson to keep your progress.
Insert at the tail
O(n); the link itself is O(1). (Real systems often keep a separate tail pointer to make this O(1) too.)The steps
- Make the new node.
- If the list is empty, the new node is the list.
- Otherwise walk
curruntilcurr.nextisnull— that's the tail. - Set
curr.next = nodeto hang it on the end.
O(n) to get there, O(1) to link — is the whole story of tail inserts.This section has a step-by-step animation in the interactive lesson.
function insertTail(head, val) {
const node = new ListNode(val);
if (!head) return node; // empty list → the node is the list
let curr = head;
while (curr.next) curr = curr.next; // walk to the tail (O(n))
curr.next = node; // link the new node on
return head;
}
const h6 = insertTail(buildList([3, 7, 1]), 9); // append 9
console.log(printVals(h6)); // [3,7,1,9]Quick check
Why is inserting at the tail O(n) but at the head O(1)?
Answer it in the interactive lesson to keep your progress.
Delete a node
.next at the node after the target. The unlinked node is simply left off the chain (the garbage collector reclaims it). No shifting — the removal itself is O(1).The steps
- If the head is the target, the new head is
head.next— done. - Otherwise walk until
curr.nextis the target node. - Skip it:
curr.next = curr.next.next.
Trace it — delete 1 from 3 → 7 → 1 → 9
- walk to
7(the node before1) - point
7.nextpast1, straight at9 - result:
3 → 7 → 9
This section has a step-by-step animation in the interactive lesson.
function deleteVal(head, target) {
if (!head) return null;
if (head.val === target) return head.next; // dropping the head itself
let curr = head;
while (curr.next && curr.next.val !== target) curr = curr.next;
if (curr.next) curr.next = curr.next.next; // skip over the target node
return head;
}
const h7 = deleteVal(buildList([3, 7, 1, 9]), 1); // remove 1
console.log(printVals(h7)); // [3,7,9]Quick check
To delete 1 from 3 → 7 → 1 → 9, the walk must stop at…
Answer it in the interactive lesson to keep your progress.
Where it breaks (and how not to get burned)
- Losing the head. The head is your only entry point — reassign it while walking without saving it and the whole list is gone. Always walk with a separate
curr. - Null dereference. Reading
curr.next.valwhencurr.nextisnullthrows. Guard the end of the chain before you step (while (curr.next)). - Rewiring in the wrong order. When you insert or delete, set the new node's
.nextbefore you overwrite the old link — otherwise you cut off the rest of the list. Save what you need first.
next before flipping the arrow. Skip that save on any step and the rest of the chain floats away, which is exactly the third pitfall in action.This section has a step-by-step animation in the interactive lesson.
Quick check
If you overwrite a node's `.next` before saving it, you…
Answer it in the interactive lesson to keep your progress.
How fast is it? (complexity)
| operation | cost | why |
|---|---|---|
| insert / remove at the head | O(1) | just relink — nothing shifts |
read node.val, step node.next | O(1) | one pointer hop |
| find or reach the k-th node | O(n) | no index — you must walk |
| insert at the tail | O(n) | walk to the end first |
| walk the whole list | O(n) time, O(1) space | visit each node once |
n nodes takes O(n) space.- A node is
{ val, next }; the head is your only way in, and the tail's.nextisnull. - Front inserts/removes are
O(1); anything by position isO(n)— the opposite trade-off from an array. - Every operation is a walk plus a little pointer surgery; save
.nextbefore you overwrite it.
.next as you go — it's this topic's Level-2 challenge, and the animation above), detect a cycle or find the middle with fast & slow pointers (the animation below — watch the fast marker take two hops for the slow one's every one), and merge two sorted lists by splicing nodes. Next up in order: Binary Search — the first algorithm that beats a plain O(n) scan by halving the search each step.This section has a step-by-step animation in the interactive lesson.