手撕xxx数据结构系列

跳表

借用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;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值