Linked lists
Adding a value at the front of a linked list changes two pointers, whether the list holds 4 values or 4 million.
Values that point to the next one
An array keeps its values side by side, which is why the front is expensive to change. A linked list drops that rule. Each value lives in its own small record called a node, and the nodes can sit anywhere in memory. MIT's 6.006 notes describe a node with two fields: the item, and next, a pointer to the following node. The list itself only remembers the first node, called the head. The last node's next is null, which marks the end.
To read the list you start at head and follow next pointers one by one, like following a chain of notes that each say where the next note is hidden. That has a cost. There is no formula for the address of the fourth node, so getting the value at position i means visiting i + 1 nodes. MIT lists get at(i) for a linked list as O(n), where the array managed it in one step.
// one node per value: { value, next }
let head = null;
for (const v of [4, 30, 7, 12]) head = { value: v, next: head };
// walk the list
for (let n = head; n !== null; n = n.next) console.log(n.value); // 12, 7, 30, 4Changing the list by relinking
The payoff comes when you change the list. To put a new value at the front, make a node whose next is the current head, then point head at the new node. Two pointer changes, and nothing else moves. Deleting the front node is one change: point head at head.next. Compare that with the array, where the same operations moved every value.
In the middle, the work is finding the spot. To insert at position i you walk to the node just before it (i visits), then do the same two pointer changes: new.next = prev.next, then prev.next = new. The order matters. If you set prev.next first, the rest of the list is lost, because nothing points to it any more. In the lab a step is one node visited or one pointer changed, so inserting at position 2 of a 4-node list costs 2 visits plus 2 changes, 4 steps.
Drag to turn. Scroll or pinch to zoom.
| Operation | Array (n values) | Linked list (n nodes) |
|---|---|---|
| Get the value at position i | 1 | i + 1 visits |
| Insert at the front | n moves + 1 write | 2 pointer changes |
| Delete the front | 1 read + (n − 1) moves | 1 pointer change |
| Insert at position i | (n − i) moves + 1 write | i visits + 2 changes |
| Find a value | up to n reads | up to n visits |
When to use one
A linked list is a good fit when most changes happen at a place you already hold a pointer to, such as the front, and you rarely need position i. Queues and stacks can be built from linked lists, and so can the chains inside a hash table in the next unit. There are variants. A doubly linked list gives each node a prev pointer too, so you can walk backwards and delete a node in one step once you have it. Keeping a tail pointer as well as head makes adding at the end cheap.
In everyday JavaScript you rarely write a linked list, because arrays are well optimized and caches in modern processors favour values stored side by side. The idea matters anyway: trees, graphs and many library structures are built from nodes and pointers in exactly this way.
- What two fields does a node of a singly linked list hold?
- item and next
- index and value
- left and right
- head and tail
- List 12 → 7 → 30 → 4. How many steps does inserting a new value at the front take (pointer changes)?
- Same list: inserting at position 2 costs how many steps (visits plus pointer changes)?
- Same list: how many nodes does a search for 30 visit?
- Same list: how many nodes does a search for 99 visit before it reaches null?
- Same list: deleting the node at position 3 (the 4) costs how many steps?
- An array holds 1,000 values with room to spare. How many steps does inserting at the front take?
- Which job suits a linked list better than an array?
- Reading the value at position 500 many times
- Adding and removing at the front many times
- Binary search
- Sorting by index
- When inserting after node p, which order of steps keeps the rest of the list?
- p.next = new, then new.next = p.next
- new.next = p.next, then p.next = new
- Either order works
- Delete p first
- Which language, written around 1956 at RAND, introduced list processing with linked cells?
- Fortran
- IPL
- C
- JavaScript
- A linked list stores each value in a node with a next pointer; the list keeps head.
- Insert or delete at the front changes 1 or 2 pointers; nothing moves.
- Reaching position i takes i + 1 visits, so get at(i) is O(n).
- Set new.next before relinking the previous node.
Sources for this course (5)
- MIT OpenCourseWare 6.006 Introduction to Algorithms, Spring 2020 (Demaine, Ku, Solomon), lecture notes 2 Data Structures (interface vs data structure, Sequence and Set interfaces, stack = insert_last/delete_last, queue = insert_last/delete_first, array, linked list, dynamic array, amortized Θ(1) append), 4 Hashing (chaining, pigeonhole collisions, chain length n/m), 6 Binary Trees Part 1 (height, traversal order, O(h) operations) and 7 Binary Trees Part 2: AVL (Adelson-Velsky and Landis, 1962) at ocw.mit.edu/courses/6-006-introduction-to-algorithms-spring-2020/pages/lecture-notes
- MDN Web Docs, Array.prototype.shift (shifts all values left by 1), Array.prototype.unshift, Map (insertion order, Map vs Object, spec requires sublinear average access) and Set (developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects)
- ECMAScript 2025 Language Specification (tc39.es/ecma262), 24.1 Map Objects and 24.2 Set Objects ("must be implemented using either hash tables or other mechanisms that, on average, provide access times that are sublinear on the number of elements"), Array.prototype.shift steps (Repeat, while k < len: move element k to k - 1)
- D. E. Knuth, The Art of Computer Programming vol. 3 (2nd ed. 1998) section 6.4 History (H. P. Luhn, IBM internal memorandum January 1953, hashing with chaining; digit pairs added mod 10, 31415926 -> 4548) via gwern.net copy, and IEEE Spectrum, "Hans Peter Luhn and the Birth of the Hashing Algorithm" (2018)
- "A brief history of the stack", SIGCIS (sigcis.org/files/A brief history.pdf: Bauer and Samelson applied for the patent in 1957, US 3,047,228 granted July 31, 1962; IPL list processing by Newell, Simon and Shaw at RAND 1956) and Wikipedia, Information Processing Language (Newell, Shaw, Simon, RAND and Carnegie Institute of Technology, about 1956).
Checked: 2026-10-18