加载中…
应用场景:Redis 有序集合 · 范围查询
交互式动画演示,可调整参数并单步执行。
全屏打开跳表(Skip List) 是一种基于有序链表的数据结构,通过建立多层索引实现 O(log n) 的查找、插入和删除。
核心思想:给链表加"快速通道",像二分查找一样跳跃前进。
graph LR L3[Level 3: 1 ---------> 9] L2[Level 2: 1 ---> 5 ---> 9] L1[Level 1: 1 -> 3 -> 5 -> 7 -> 9] L0[Level 0: 1->2->3->4->5->6->7->8->9]
查找 7:Level 3 跳到 9(太大)→ Level 2 跳到 5 → Level 1 跳到 7 ✅
| 数据结构 | 查找 | 插入/删除 | 实现难度 |
|---|---|---|---|
| 有序数组 | O(log n) | O(n) | 简单 |
| 有序链表 | O(n) | O(1)(已知位置) | 简单 |
| BST / AVL | O(log n) | O(log n) | 复杂 |
| 跳表 | O(log n) | O(log n) | 中等 |
跳表的优势:
Redis 的有序集合(ZSet)底层就是跳表 + 哈希表。
从最高层开始,向右走到不能走(下一个 > target),就下降一层:
public boolean search(int target) {
Node cur = head;
for (int level = maxLevel - 1; level >= 0; level--) {
while (cur.next[level] != null && cur.next[level].val < target) {
cur = cur.next[level];
}
}
cur = cur.next[0]; // 底层下一个
return cur != null && cur.val == target;
}public void insert(int val) {
Node[] update = new Node[maxLevel];
Node cur = head;
for (int level = maxLevel - 1; level >= 0; level--) {
while (cur.next[level] != null && cur.next[level].val < val) {
cur = cur.next[level];
}
update[level] = cur;
}
int newLevel = randomLevel();
Node newNode = new Node(val, newLevel);
for (int i = 0; i < newLevel; i++) {
newNode.next[i] = update[i].next[i];
update[i].next[i] = newNode;
}
}private int randomLevel() {
int level = 1;
while (Math.random() < 0.5 && level < maxLevel) {
level++;
}
return level;
}每个节点有 50% 概率晋升一层。期望层数 = 2,最高层 ≈ log₂(n)。
public boolean delete(int val) {
Node[] update = new Node[maxLevel];
Node cur = head;
for (int level = maxLevel - 1; level >= 0; level--) {
while (cur.next[level] != null && cur.next[level].val < val) {
cur = cur.next[level];
}
update[level] = cur;
}
cur = cur.next[0];
if (cur == null || cur.val != val) return false;
for (int i = 0; i < cur.next.length; i++) {
update[i].next[i] = cur.next[i];
}
return true;
}| 操作 | 期望时间 | 最坏时间 | 空间 |
|---|---|---|---|
| 查找 | O(log n) | O(n) | — |
| 插入 | O(log n) | O(n) | O(log n) |
| 删除 | O(log n) | O(n) | — |
| 总空间 | — | — | O(n) |
期望意义下与平衡树相同,但实现简单得多。
| 维度 | 跳表 | 红黑树 | B+ 树 |
|---|---|---|---|
| 实现复杂度 | 低 | 高 | 高 |
| 范围查询 | 优秀(链表遍历) | 需中序遍历 | 优秀(叶节点链表) |
| 并发性能 | 好(局部锁) | 一般 | 好 |
| 内存局部性 | 一般 | 一般 | 好(磁盘友好) |
| 典型应用 | Redis ZSet | Java TreeMap | MySQL 索引 |
Redis ZSet 的跳表实现有几个工程细节:
maxLevel = 16 或 32,避免无限晋升。