跳表
2024年8月18日大约 2 分钟
跳表
- OI Wiki: https://oi-wiki.org/ds/skiplist/
| 题目 | 难度 | |
|---|---|---|
| 1206. 设计跳表 | 困难 |
基本思想
跳表 (Skip List) 是由 William Pugh 发明的一种查找数据结构,支持对数据的快速查找,插入和删除。
跳表的期望空间复杂度为 O(n),跳表的查询,插入和删除操作的期望时间复杂度都为 O(log n)。
1206. 设计跳表
import java.util.Arrays; import java.util.Random; public class Solution1206 { static class Skiplist { private static final int MAX_LEVEL = 32; // 以 p 的概率往上加一层,最后和上限值取最小。 private static final double P = 0.25; private final Random random; private final SkiplistNode head; private int level; public Skiplist() { head = new SkiplistNode(-1, MAX_LEVEL); level = 0; random = new Random(); } public boolean search(int target) { SkiplistNode cur = head; for (int i = level - 1; i >= 0; i--) { // 找到第 i 层小于且最接近 target 的元素 while (cur.forward[i] != null && cur.forward[i].val < target) { cur = cur.forward[i]; } } cur = cur.forward[0]; return (cur != null) && (cur.val == target); } public void add(int num) { SkiplistNode[] update = new SkiplistNode[MAX_LEVEL]; Arrays.fill(update, head); SkiplistNode cur = head; for (int i = level - 1; i >= 0; i--) { // 找到第 i 层小于且最接近 num 的元素 while (cur.forward[i] != null && cur.forward[i].val < num) { cur = cur.forward[i]; } update[i] = cur; } int lv = randomLevel(); level = Math.max(level, lv); SkiplistNode newNode = new SkiplistNode(num, lv); for (int i = 0; i < lv; i++) { // 对第 i 层状态进行更新,将当前元素的 forward 指向新的节点 newNode.forward[i] = update[i].forward[i]; update[i].forward[i] = newNode; } } public boolean erase(int num) { SkiplistNode[] update = new SkiplistNode[MAX_LEVEL]; // Arrays.fill(update, head); SkiplistNode cur = head; for (int i = level - 1; i >= 0; i--) { // 找到第 i 层小于且最接近 num 的元素 while (cur.forward[i] != null && cur.forward[i].val < num) { cur = cur.forward[i]; } update[i] = cur; } cur = cur.forward[0]; if (cur == null || cur.val != num) { return false; } for (int i = 0; i < level; i++) { if (update[i].forward[i] != cur) { break; } update[i].forward[i] = cur.forward[i]; } while (level > 1 && head.forward[level - 1] == null) { level--; } return true; } private int randomLevel() { int lv = 1; // nextDouble()方法用于从此随机数生成器的序列中获取下一个伪随机、均匀分布的双精度值,该值介于 0.0 和 1.0 之间。 while (random.nextDouble() < P && lv < MAX_LEVEL) { lv++; } return lv; } private static class SkiplistNode { int val; SkiplistNode[] forward; public SkiplistNode(int val, int maxLevel) { this.val = val; this.forward = new SkiplistNode[maxLevel]; } } } }(全文完)