Skip List
A randomized alternative to balanced trees for ordered data. Every item lives in an ordinary sorted linked list, but coin flips promote some items into higher "express lanes" that let search, insert, and delete skip over long runs of the list in expected O(log n) time, no rotations or rebalancing required.
How it works
The bottom lane (level 0) is a plain sorted linked list containing every key. When a key is inserted, its height (how many lanes it participates in) is chosen by repeated coin flips: start at level 0, and for as long as the flip comes up heads (probability p, usually 0.5), climb one more level. This makes roughly half as many nodes reach each successive level, forming express lanes that shortcut over the bottom list the same way an express train skips local stops.
search() starts at the top-most lane at the head node and moves forward as long as the next node's key is still less than the target. When the next node would overshoot (or there is no next node in that lane), it drops down one level and continues -- repeating until it reaches level 0, where the next node is either the target or proof it doesn't exist.
insert() runs the same downward walk, remembering the last node visited at each level (the "update" list). The new node is spliced in at level 0 and at every level up to its randomly chosen height, re-pointing each remembered predecessor's forward pointer. delete() does the same walk and un-splices the node from every level it appeared in.
Interactive demo
API surface
| Operation | Description | Complexity |
|---|---|---|
| new SkipList(maxLevel?, p?) | Allocate a sentinel head node with maxLevel lanes; p is the per-level promotion probability. | O(maxLevel) space overhead |
| insert(key): boolean | Insert a key at a randomly chosen height, splicing it into every lane up to that height. | O(log n) expected |
| search(key) / contains(key): boolean | Walk down from the top lane, following forward pointers that stay below the target. | O(log n) expected |
| delete(key): boolean | Locate the key and un-splice it from every lane it appears in. | O(log n) expected |
| toSortedKeys(): number[] | Read off all keys in ascending order from the bottom lane. | O(n) time |
References
Original papers
- Skip Lists: A Probabilistic Alternative to Balanced TreesWilliam Pugh · 1990
Library implementations
Real-world use cases
- Redis sorted sets (ZADD/ZRANGE/ZRANGEBYSCORE), which pair a skip list with a hash table for O(log n) ordered access plus O(1) member lookup
- LevelDB and RocksDB in-memory memtables, which buffer recent writes in a skip list before flushing to sorted on-disk files
- Apache Lucene, which historically used skip lists to accelerate postings-list traversal
- java.util.concurrent.ConcurrentSkipListMap/Set, the JDK's lock-free concurrent ordered map, built directly on skip lists for scalable multi-threaded access