跳至主要內容

跳表

大约 2 分钟

跳表

题目难度
1206. 设计跳表open in new window困难

基本思想

跳表 (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];
            }
        }
    }
}

(全文完)