Skip list visualizer
A skip list is a sorted linked list with express lanes: each node also sits on a random number of higher levels, so a search can skip ahead and drop down only near its target. Build one from your own keys, with random heights or the heights from your exercise, and follow every search step.
moved right throughcompared and dropped downthe key
Insert 80 with height 2 (coin flips with p = 0.5): link it in after 70 on levels 1 to 2. 3 comparisons.
- 1On level 5, 20 < 80: move right to 20.
- 2On level 5, nothing follows 20: drop down.
- 3On level 4, 40 < 80: move right to 40.
- 4On level 4, 70 < 80: move right to 70.
- 5On level 4, nothing follows 70: drop down.
- 6On level 3, nothing follows 70: drop down.
- 7On level 2, nothing follows 70: drop down.
- 8On level 1, nothing follows 70: drop down.
- 9Insert 80 with height 2 (coin flips with p = 0.5): link it in after 70 on levels 1 to 2.
10:1 20:5 30:3 40:4 50:2 60:2 70:4 80:2
How to use the simulator
Type the keys to insert, in order, and press "Build list". A key on its own gets a random height from coin flips with probability p; write 30:3 to give 30 height 3, as many exercises specify, and x30 to delete 30. Then search, insert or delete single keys: the drawing marks the nodes the search moved through and where it dropped down, and the side panel lists every comparison.
- "Flip the coins again" rebuilds the same keys with new random heights, so you can see how much the shape varies.
- "Copy link" saves the keys, heights and coin flips in the address.
What is a skip list?
A skip list keeps keys in a sorted linked list, the bottom level, and adds higher levels that each contain a random subset of the level below. Every node is on level 1; with probability p it is also on level 2, with probability p² on level 3, and so on. The higher levels act as express lanes: a search runs along the top, where nodes are far apart, and drops a level whenever it would overshoot.
Because heights are chosen at random when a node is inserted and never changed, a skip list needs none of the rotations or recolouring of balanced trees. The price is that its O(log n) cost holds only on average, over the coin flips, not in every case.
Search, insert and delete
- Search starts at the head on the highest level, moves right while the next key is smaller than the target, and drops down a level when the next key is larger or missing. On level 1, the next node is either the target or proof that it is absent.
- Insert runs the same search, remembering the last node visited on every level, draws the new node's height, and links it in after those nodes on each of its levels.
- Delete runs the search and unlinks the node on every level it occupies; if the top levels become empty, the list's height shrinks.
How fast it is
William Pugh's analysis bounds the expected cost of a search in a list of n keys by L/p + 1/(1 − p) steps, where L = log1/p n. Average comparisons per successful search in this page's model, over random lists, against that bound:
| p | Keys | Comparisons | Pugh's bound | Pointers per node | Levels |
|---|---|---|---|---|---|
| 1/2 | 100 | 10.8 | 15.3 | 1.89 | 7 |
| 1/2 | 1,000 | 20.8 | 21.9 | 2.04 | 10 |
| 1/2 | 10,000 | 23.6 | 28.6 | 2.00 | 13 |
| 1/2 | 100,000 | 31.7 | 35.2 | 1.99 | 16 |
| 1/4 | 100 | 11.0 | 14.6 | 1.34 | 4 |
| 1/4 | 1,000 | 18.1 | 21.3 | 1.36 | 6 |
| 1/4 | 10,000 | 23.6 | 27.9 | 1.34 | 9 |
| 1/4 | 100,000 | 29.5 | 34.6 | 1.33 | 10 |
The cost grows with the logarithm of n: a thousand times more keys adds only a handful of comparisons. Choosing p = 1/4 instead of 1/2 cuts the pointers per node from about 2 to about 1.33, since a node has 1/(1 − p) pointers on average, and costs almost nothing in search time, which is why Redis and LevelDB use 1/4.
Where skip lists are used
- Redis sorted sets. Large sorted sets are a skip list plus a hash table; the source sets p = 1/4 and at most 32 levels, and each link stores how many nodes it spans so that rank queries are fast.
- LevelDB and RocksDB memtables. LevelDB's in-memory table is a skip list with a branching factor of 4 and at most 12 levels. Writers need a lock, but reads proceed without any locking.
- Java's ConcurrentSkipListMap provides a sorted concurrent map with expected logarithmic cost, which is simpler to build without locks than a balanced tree.
Skip lists and balanced trees
Both give logarithmic search, insertion and deletion, and both keep keys in order for range scans. A balanced tree such as a red-black tree guarantees its bound in the worst case and tends to use memory more compactly. A skip list is shorter to write, needs no rebalancing, and an insertion only touches the pointers next to the new node, which makes concurrent versions much easier. The bottom level is a plain linked list, so iterating in order is trivial.
History
William Pugh of the University of Maryland introduced skip lists in "Skip Lists: A Probabilistic Alternative to Balanced Trees" in Communications of the ACM in 1990, arguing that they match balanced trees in expected performance while being simpler to implement. They became a standard part of data structure courses and, later, of databases and key-value stores that need ordered, concurrent in-memory indexes.
Skip list questions and answers
How does search work in a skip list?
Start at the head on the highest level. Move right while the next node’s key is smaller than the one you want; when the next key is larger, or there is none, drop down a level. Repeat until you reach the bottom level, where the next node is either the key or proof that it is absent. Each level skips over roughly 1/p nodes of the level below.
How is a node’s height chosen?
By flipping a biased coin: every node is on level 1, and it is promoted to each next level with probability p, usually 1/2 or 1/4, up to a maximum. A node’s height never changes after insertion, and no rebalancing is ever needed. Textbook exercises often fix the heights instead, which this page supports with the key:height notation.
What is the time complexity of a skip list?
Search, insert and delete take O(log n) time on average, and O(n) in the unlikely worst case where the coin flips go badly. With p = 1/2 and 100,000 keys, a search in this page’s model made 31.7 comparisons on average, under Pugh’s bound of 35.2.
Why does Redis use a skip list for sorted sets?
A sorted set needs lookups by score, ordered range scans and rank queries. A skip list gives all three with simple code, ranges are a walk along the bottom level, and Redis adds a span to each link so it can compute ranks. Redis pairs it with a hash table for lookups by member, and uses p = 1/4 with at most 32 levels.
Skip list or balanced tree?
Both give O(log n) operations. A skip list is simpler to write, needs no rotations, and is easier to make concurrent, because an insert only changes a few local pointers; LevelDB’s memtable and Java’s ConcurrentSkipListMap use one. A balanced tree gives worst-case guarantees, and usually better cache behaviour.
What does the probability p change?
Smaller p means fewer pointers per node but more steps per level. With 100,000 keys, p = 1/2 used 1.99 pointers per node and 31.7 comparisons per search; p = 1/4 used 1.33 pointers and 29.5 comparisons.
Further reading
- Pugh, Communications of the ACM, 1990Skip lists: a probabilistic alternative to balanced treesThe original paper, with the analysis of expected cost.
- Redis sourcet_zset.cThe sorted set skip list, with spans for ranks.
- LevelDB sourceskiplist.hA compact skip list with lock-free reads.
- Java documentationConcurrentSkipListMapA concurrent sorted map built on a skip list.