跳表

0001 年 1 月 1 日

目录

理论

key-value 键值对快速增删查改,复杂度同红黑树,实现较为简单。

代码

#ifndef ALGO_DATASTRUCT_SKIPLIST
#define ALGO_DATASTRUCT_SKIPLIST

#include "../base.hpp"

#include <array>
#include <optional>
#include <queue>
#include <random>

template <typename K, typename V>
struct SkipList {
  enum : u64 {
    MAXL = 32,                                 // 最大层数
    P = 4,                                     // 概率(1 / 4)
    S = 0xFFFF,                                // 限制随机值
    PS = S / P,                                // 概率
    INVALID = std::numeric_limits<u64>::max(), // 最大值(哨兵)
  };
  /*
      跳表结点(层数,值,指针)
  */
  struct SkipListNode {
    K key;
    V value;
    i32 level{};
    SkipListNode **forward;
    SkipListNode() = default;
    SkipListNode(K k, V v, i32 l, SkipListNode *nxt = nullptr) {
      key = k;
      value = v;
      level = l;
      forward = new SkipListNode *[l + 1];
      for (i32 i = 0; i <= l; ++i)
        forward[i] = nxt;
    }
    ~SkipListNode() {
      delete[] forward;
    }
  };
  using Node = SkipListNode;
  Node *head, *tail; // 两排哨兵
  i32 length;        // 链表长度 L0 层
  i32 level;         // 层数
  std::mt19937 rng;
  SkipList() : rng(std::random_device{}()) {
    level = length = 0;
    tail = new Node(INVALID, 0, 0);
    head = new Node(INVALID, 0, MAXL, tail);
  }
  ~SkipList() {
    delete head;
    delete tail;
  }
  
  /*
      第一层 50 % , 第二层 25 % ,第三层 12.5% 依此类推, P = 1 / 4
  */
  i32 randomLevel() {
    i32 lv = 1;
    while ((rng() & S) < PS)
      ++lv;
    return MAXL > lv ? lv : MAXL;
  }
  /*
      插入新结点,
  */
  V &insert(const K &key, const V &value) {
    std::array<Node *, MAXL + 1> update{};
    Node *p = head;
    for (i32 i = level; i >= 0; --i) {
      while (p->forward[i]->key < key) {
        p = p->forward[i];
      }
      update[i] = p;
    }
    p = p->forward[0];
    if (p->key == key) {
      return p->value = value;
    }
    i32 lv = randomLevel();
    if (lv > level) { // 一次只会比当前层数高一层
      lv = ++level;
      update[lv] = head;
    }
    Node *newNode = new Node(key, value, lv);
    for (i32 i = lv; i >= 0; --i) {
      p = update[i];
      newNode->forward[i] = p->forward[i];
      p->forward[i] = newNode;
    }
    ++length;
    return newNode->value;
  }
  bool erase(const K &key) {
    std::array<Node *, MAXL + 1> update;
    Node *p = head;
    for (i32 i = level; i >= 0; --i) {
      while (p->forward[i]->key < key) {
        p = p->forward[i];
      }
      update[i] = p;
    }
    p = p->forward[0];
    if (p->key != key)
      return false;
    for (i32 i = 0; i <= level; ++i) {
      if (update[i]->forward[i] != p) {
        break;
      }
      update[i]->forward[i] = p->forward[i];
    }
    delete p;
    while (level > 0 && head->forward[level] == tail)
      --level;
    --length;
    return true;
  }
  std::optional<V> find(const K &key) {
    Node *p = head;
    for (i32 i = level; i >= 0; --i) {
      while (p->forward[i]->key < key) {
        p = p->forward[i];
      }
    }
    p = p->forward[0];
    if (p->key == key)
      return p->value;
    return std::nullopt;
  }
  V &operator[](const K &key) {
    Node *p = head;
    for (i32 i = level; i >= 0; --i) {
      while (p->forward[i]->key < key) {
        p = p->forward[i];
      }
    }
    p = p->forward[0];
    if (p->key == key) {
      return p->value;
    } else {
      return insert(key, 0);
    }
  }
  bool count(const K &key) {
    return find(key) != tail->value;
  }
};

#endif