A skip list is a probabilistic ordered structure: a base linked list with multiple "express lane" forwarding pointers above it. Each node is randomly promoted to higher levels, giving O(log n) expected search/insert/delete. Used in Redis sorted sets, LevelDB, and Java's ConcurrentSkipListMap.
| Average | Worst | Space | ||||||
|---|---|---|---|---|---|---|---|---|
| Access | Search | Insertion | Deletion | Access | Search | Insertion | Deletion | Worst |
Θ(log n) |
Θ(log n) |
Θ(log n) |
Θ(log n) |
O(n) |
O(n) |
O(n) |
O(n) |
O(n log n) |
Insert: flip a coin to choose a level (geometric distribution — half of nodes at level 0, a quarter at level 1, etc.). Search: start at the top level, walk forward until the next key is too large, drop down a level, repeat. Each level halves the work, giving expected O(log n).
import random
MAX_LEVEL = 16
P = 0.5
class _Node:
__slots__ = ("key", "forward")
def __init__(self, key, level):
self.key = key
self.forward = [None] * (level + 1)
class SkipList:
def __init__(self):
self.head = _Node(None, MAX_LEVEL)
self.level = 0
def _random_level(self):
lv = 0
while random.random() < P and lv < MAX_LEVEL:
lv += 1
return lv
def search(self, key): # O(log n) expected
x = self.head
for i in range(self.level, -1, -1):
while x.forward[i] and x.forward[i].key < key:
x = x.forward[i]
x = x.forward[0]
return x is not None and x.key == key
def insert(self, key): # O(log n) expected
update = [self.head] * (MAX_LEVEL + 1)
x = self.head
for i in range(self.level, -1, -1):
while x.forward[i] and x.forward[i].key < key:
x = x.forward[i]
update[i] = x
lv = self._random_level()
if lv > self.level:
self.level = lv
n = _Node(key, lv)
for i in range(lv + 1):
n.forward[i] = update[i].forward[i]
update[i].forward[i] = n
sl = SkipList()
for k in [3, 6, 1, 8, 2, 9, 4]:
sl.insert(k)
print(sl.search(8)) # True
print(sl.search(7)) # False
ConcurrentSkipListMap.