[数据结构] 跳表

142 阅读1分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

跳表

跳表是在O(log(n))时间内完成增加、删除、搜索操作的数据结构。跳表 是在 O(log(n)) 时间内完成增加、删除、搜索操作的数据结构。 跳表相比于树堆与红黑树,其功能与性能相当,跳表相比于树堆与红黑树,其功能与性能相当, 并且跳表的代码长度相较下更短,其设计思想与链表相似。并且跳表的代码长度相较下更短,其设计思想与链表相似。

例如,一个跳表包含[30,40,50,60,70,90]例如,一个跳表包含 [30, 40, 50, 60, 70, 90] , 然后增加8045到跳表中,以下图的方式操作:然后增加 80、45 到跳表中,以下图的方式操作: 跳表中有很多层,每一层是一个短的链表。跳表中有很多层,每一层是一个短的链表。 在第一层的作用下,增加、删除和搜索操作的时间复杂度不超过O(n)在第一层的作用下,增加、删除和搜索操作的时间复杂度不超过 O(n)。 跳表的每一个操作的平均时间复杂度是O(log(n)),空间复杂度是O(n)跳表的每一个操作的平均时间复杂度是 O(log(n)),空间复杂度是 O(n)。

boolsearch(inttarget):返回target是否存在于跳表中。 bool search(int target) : 返回target是否存在于跳表中。 voidadd(intnum): 插入一个元素到跳表。void add(int num): 插入一个元素到跳表。 boolerase(intnum):在跳表中删除一个值,如果 num 不存在,直接返回false.bool erase(int num): 在跳表中删除一个值,如果 num 不存在,直接返回false. 如果存在多个 num ,删除其中任意一个即可。如果存在多个 num ,删除其中任意一个即可。

借用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;
    }
};