LeetCode //C - 1206. Design Skiplist

1206. Design Skiplist

Design a Skiplist without using any built-in libraries.

A skiplist is a data structure that takes O(log(n)) time to add, erase and search. Comparing with treap and red-black tree which has the same function and performance, the code length of Skiplist can be comparatively short and the idea behind Skiplists is just simple linked lists.

For example, we have a Skiplist containing 30,40,50,60,70,90 and we want to add 80 and 45 into it. The Skiplist works this way:

You can see there are many layers in the Skiplist. Each layer is a sorted linked list. With the help of the top layers, add, erase and search can be faster than O(n). It can be proven that the average time complexity for each operation is O(log(n)) and space complexity is O(n).

See more about Skiplist: https://en.wikipedia.org/wiki/Skip_list

Implement the Skiplist class:

  • Skiplist() Initializes the object of the skiplist.
  • bool search(int target) Returns true if the integer target exists in the Skiplist or false otherwise.
  • void add(int num) Inserts the value num into the SkipList.
  • bool erase(int num) Removes the value num from the Skiplist and returns true. If num does not exist in the Skiplist, do nothing and return false. If there exist multiple num values, removing any one of them is fine.

Note that duplicates may exist in the Skiplist, your code needs to handle this situation.

Example 1:

Input:

"Skiplist", "add", "add", "add", "search", "add", "search", "erase", "erase", "search"

\[\], \[1\], \[2\], \[3\], \[0\], \[4\], \[1\], \[0\], \[1\], \[1\]

Output:

null, null, null, null, false, null, true, false, true, false

Explanation

Skiplist skiplist = new Skiplist();

skiplist.add(1);

skiplist.add(2);

skiplist.add(3);

skiplist.search(0); // return False

skiplist.add(4);

skiplist.search(1); // return True

skiplist.erase(0); // return False, 0 is not in skiplist.

skiplist.erase(1); // return True

skiplist.search(1); // return False, 1 has already been erased.

Constraints:
  • 0 < = n u m , t a r g e t < = 2 ∗ 10 4 0 <= num, target <= 2 * 10^4 0<=num,target<=2∗104
  • At most 5 ∗ 10 4 5 * 10^4 5∗104 calls will be made to search, add, and erase.

From: LeetCode

Link: 1206. Design Skiplist


Solution:

Ideas:

add, search, and erase all move from the highest level down to level 0, so the average time complexity is O(log n).

Code:
c 复制代码
#define MAX_LEVEL 32

typedef struct Node {
    int val;
    struct Node* forward[MAX_LEVEL];
} Node;

typedef struct {
    Node* head;
    int level;
} Skiplist;

Node* createNode(int val) {
    Node* node = (Node*)malloc(sizeof(Node));
    node->val = val;
    for (int i = 0; i < MAX_LEVEL; i++) {
        node->forward[i] = NULL;
    }
    return node;
}

int randomLevel() {
    int level = 1;
    while ((rand() & 1) && level < MAX_LEVEL) {
        level++;
    }
    return level;
}

Skiplist* skiplistCreate() {
    Skiplist* obj = (Skiplist*)malloc(sizeof(Skiplist));
    obj->head = createNode(-1);
    obj->level = 1;
    return obj;
}

bool skiplistSearch(Skiplist* obj, int target) {
    Node* cur = obj->head;

    for (int i = obj->level - 1; i >= 0; i--) {
        while (cur->forward[i] && cur->forward[i]->val < target) {
            cur = cur->forward[i];
        }
    }

    cur = cur->forward[0];
    return cur && cur->val == target;
}

void skiplistAdd(Skiplist* obj, int num) {
    Node* update[MAX_LEVEL];
    Node* cur = obj->head;

    for (int i = obj->level - 1; i >= 0; i--) {
        while (cur->forward[i] && cur->forward[i]->val < num) {
            cur = cur->forward[i];
        }
        update[i] = cur;
    }

    int lv = randomLevel();

    if (lv > obj->level) {
        for (int i = obj->level; i < lv; i++) {
            update[i] = obj->head;
        }
        obj->level = lv;
    }

    Node* node = createNode(num);

    for (int i = 0; i < lv; i++) {
        node->forward[i] = update[i]->forward[i];
        update[i]->forward[i] = node;
    }
}

bool skiplistErase(Skiplist* obj, int num) {
    Node* update[MAX_LEVEL];
    Node* cur = obj->head;

    for (int i = obj->level - 1; i >= 0; i--) {
        while (cur->forward[i] && cur->forward[i]->val < num) {
            cur = cur->forward[i];
        }
        update[i] = cur;
    }

    cur = cur->forward[0];

    if (!cur || cur->val != num) {
        return false;
    }

    for (int i = 0; i < obj->level; i++) {
        if (update[i]->forward[i] != cur) {
            break;
        }
        update[i]->forward[i] = cur->forward[i];
    }

    free(cur);

    while (obj->level > 1 && obj->head->forward[obj->level - 1] == NULL) {
        obj->level--;
    }

    return true;
}

void skiplistFree(Skiplist* obj) {
    Node* cur = obj->head;

    while (cur) {
        Node* next = cur->forward[0];
        free(cur);
        cur = next;
    }

    free(obj);
}
相关推荐
wuminyu21 分钟前
Kafka中sendfile与mmap实现机制解析
java·linux·c语言·jvm·c++
GreenTea2 小时前
vLLM 与 SGLang KV Cache 底层实现机制深度调研报告
前端·后端·算法
Blockbuater_drug2 小时前
FreeSASA: 开源 SASA 计算库,pip 一条命令替代 NACCESS
c语言·开源·sasa·freesasa·溶剂可及表面积·naccess·python api
Bode_20022 小时前
多资源规划(含生产调度、库存管理及产能规划)的创新优化算法
算法·调度
Logic1012 小时前
C语言/数据结构位运算题解:异或XOR找出蛋糕订单中的“VIP独特口味“——只出现一次的数字
c语言·数据结构·数组·位运算·时间复杂度·算法题·异或性质
土司大王3 小时前
LeetCode hot100——35.搜索插入位置:Java 二分模板、左闭右开区间与插入点分析
java·算法·leetcode
微三云生态系统架构师-彭丹3 小时前
远方好物S2B2C系统架构:一级分销与保证金托管的合规技术实现
人工智能·算法
土司大王3 小时前
LeetCode hot100——34.在排序数组中查找元素的第一个和最后一个位置:Java 二分模板、边界分析
java·算法·leetcode
Logic1013 小时前
C语言/数据结构位运算题解:异或XOR找出飞行棋中的“独特颜色棋子“——只出现一次的数字
c语言·数据结构·数组·位运算·时间复杂度·算法题·异或性质
罗西的思考4 小时前
机器人模型(WM / WAM / VLA)综合分析与对比:从「看」到「想」再到「做」
人工智能·算法·机器学习