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);
}
相关推荐
学逆向的1 天前
C 枚举变量
c语言·开发语言·网络安全
冷凝雨1 天前
前导零、后导零、最高有效位、最低有效位计算(C)
c语言
鸥梨菌Honevid1 天前
C 语言 restrict 关键字深度解析:从“独占访问”承诺到编译器激进优化
c语言
企业数字化笔记1 天前
视频人体姿态怎么做三维可视化?2D关键点、深度局限与技术选型
人工智能·算法·音视频
?abc!1 天前
(数组)581. 最短无序连续子数组
数据结构·算法·leetcode
小郎君6581 天前
MPTT树复选框的半选状态:一棵百万节点树从递归到计数器,再到区间覆盖
算法
酌沧1 天前
MemT让记忆成为模型内生能力
jvm·人工智能·算法
水饺编程1 天前
第2章:Linux 基础,切换用户
linux·c语言·汇编
hold?fish:palm1 天前
40 二叉树的直径
c++·leetcode
Shimeri1 天前
越卷越像:我用遗传算法做了个"内卷"实验
算法·three.js·数据可视化·遗传算法·进化算法