跳表
借用leetcode 1206 这一道题来实现跳表
跳表本质上是利用空间换取时间的方式
若是一个离线(不修改)的跳表,最好的方式应该是每一层都去 1/2 隔开个元素
若是在线的一个跳表,那么显然需要让他们尽可能的保持平均每层选取1/2个元素来搞
从每一层找到比这个元素小的那个节点还是比较好找的
和图里面这个样子一样
跳表逻辑:
const int LEVEL = 32;
const double P_fact = 0.25;
class Skiplist {
struct node {
int val_;
vector<node*> next_;
node(int val, int maxlevel = LEVEL): val_(val),
next_(maxlevel, nullptr){}
};
node* head;
int level;
mt19937 gen{random_device{}()};
uniform_real_distribution<double> dis;
void each(vector<node*>& memo, int v) {
node* cur = head;
for (int i = level - 1; i >= 0; -- i) {
while (cur->next_[i] && cur->next_[i]->val_ < v)
cur = cur->next_[i];
memo[i] = cur;
}
}
public:
Skiplist():head(new node(-1)), level(0), dis(0, 1) {}
bool search(int target) {
vector<node*> memo(LEVEL, head);
each(memo, target);
node* res = memo[0]->next_[0];
if (res && res->val_ == target) return true;
return false;
}
void add(int num) {
vector<node*> memo(LEVEL, head);
each(memo, num);
int lv = randLevel();
level = max(lv, level);
node* newNode = new node(num, lv);
for (int i = 0; i < lv; ++ i) {
newNode->next_[i] = memo[i]->next_[i];
memo[i]->next_[i] = newNode;
}
}
bool erase(int num) {
vector<node*> memo(LEVEL, head);
each(memo, num);
node* cur = memo[0]->next_[0];
if (!cur || cur->val_ != num) return false;
for (int i = 0; i < level; ++ i) {
if (memo[i]->next_[i] != cur) break;
memo[i]->next_[i] = cur->next_[i];
}
delete cur;
while (level > 1 && head->next_[level - 1] == nullptr) level --;
return true;
}
int randLevel() {
int lv = 1;
while (dis(gen) < P_fact && lv < LEVEL) lv ++;
return lv;
}
};