From 1b1ac57a9c0f33717dad9d8e800f8d877e734aa3 Mon Sep 17 00:00:00 2001 From: abbycin Date: Sun, 29 May 2022 12:59:32 +0800 Subject: [PATCH] add skiplist --- skiplist/CMakeLists.txt | 1 + skiplist/main.cc | 36 ++++++ skiplist/skiplist.h | 272 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 309 insertions(+) create mode 100644 skiplist/CMakeLists.txt create mode 100644 skiplist/main.cc create mode 100644 skiplist/skiplist.h diff --git a/skiplist/CMakeLists.txt b/skiplist/CMakeLists.txt new file mode 100644 index 0000000..fa6372d --- /dev/null +++ b/skiplist/CMakeLists.txt @@ -0,0 +1 @@ +add_executable(skiplist skiplist.h main.cc) \ No newline at end of file diff --git a/skiplist/main.cc b/skiplist/main.cc new file mode 100644 index 0000000..dead60b --- /dev/null +++ b/skiplist/main.cc @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Author: Abby Cin + * Mail: abbytsing@gmail.com + * Create Time: 2022-05-24 21:35:52 + */ + +#include "skiplist.h" +#include + +int main() +{ + using nm::SkipList; + SkipList sl {}; + + for (int i = 0; i < 10; ++i) + sl.insert(i, rand() % 20); + + std::cout << std::boolalpha; + std::cout << "contains key 4?" << sl.contains(4) << '\n'; + std::cout << "rm exist key ok? " << sl.remove(4) << '\n'; + std::cout << "size " << sl.size() << '\n'; + std::cout << "rm none exist key ok? " << sl.remove(233) << '\n'; + std::cout << "size " << sl.size() << '\n'; + + std::cout << "iterate\n"; + for (auto& x : sl) + std::cout << x.first << " : " << x.second << '\n'; + + std::cout << "range\n"; + auto [b, e] = sl.range(4, 6); + while (b != e) { + printf("%d => %d\n", b.key(), b.val()); + ++b; + } +} \ No newline at end of file diff --git a/skiplist/skiplist.h b/skiplist/skiplist.h new file mode 100644 index 0000000..21036e5 --- /dev/null +++ b/skiplist/skiplist.h @@ -0,0 +1,272 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Author: Abby Cin + * Mail: abbytsing@gmail.com + * Create Time: 2022-05-24 20:51:33 + */ + +#ifndef SKIPLIST_1653396693_H_ +#define SKIPLIST_1653396693_H_ + +#include +#include +#include +#include + +namespace nm +{ +template +class SkipList { + static_assert(LEVEL > 0, "level must greater than 0"); + class Node { + public: + Node(int level) : key_ {}, val_ {}, level_ { level } + { + layer_ = new Node *[level_ + 1] { 0 }; + } + + Node(K k, V v, int level) + : key_ { k }, val_ { v }, level_ { level } + { + // level + 1, since we will index using level, namely + // range in [0, level] + layer_ = new Node *[level + 1] { 0 }; + } + + ~Node() + { + delete[] layer_; + } + + private: + friend SkipList; + K key_; + V val_; + int level_; + Node **layer_; + }; + +public: + class iterator { + public: + iterator(Node *n) : node_ { n } + { + if (node_) + p_ = std::make_pair(node_->key_, node_->val_); + } + + iterator &operator++() + { + if (node_) + new (this)iterator{node_->layer_[0]}; + else + throw std::out_of_range("iterator out range"); + return *this; + } + + std::pair& operator *() + { + return p_; + } + + K &key() + { + return node_->key_; + } + + V &val() + { + return node_->val_; + } + + friend bool operator==(const iterator &l, const iterator &r) + { + return l.node_ == r.node_; + } + + friend bool operator!=(const iterator &l, const iterator &r) + { + return !(l == r); + } + + private: + std::pair p_; + Node *node_; + }; + + SkipList() : cur_ { 0 }, size_ { 0 } + { + header_ = new Node { LEVEL }; + } + + ~SkipList() + { + cleanup(header_); + header_ = nullptr; + size_ = 0; + cur_ = 0; + } + + bool insert(K key, V value) + { + Node *update[LEVEL + 1] { 0 }; + Node *cur = header_; + int level; + int i; + + for (i = cur_; i >= 0; i--) { + while (cur->layer_[i] && cur->layer_[i]->key_ < key) + cur = cur->layer_[i]; + + update[i] = cur; + } + + cur = cur->layer_[0]; + + // already exists + if (cur && cur->key_ == key) + return false; + + level = gen_random_level(); + + // in this case, we create a new level by set update to header_ + if (level > cur_) { + for (i = cur_ + 1; i < level + 1; i++) + update[i] = header_; + cur_ = level; + } + + cur = new Node { key, value, level }; + + // insert to each level + for (i = 0; i <= level; i++) { + cur->layer_[i] = update[i]->layer_[i]; + update[i]->layer_[i] = cur; + } + + size_++; + return true; + } + + bool contains(K key) + { + Node *cur = header_; + + for (int i = cur_; i >= 0; i--) { + while (cur->layer_[i] && cur->layer_[i]->key_ < key) + cur = cur->layer_[i]; + } + + return cur && cur->layer_[0]->key_ == key; + } + + std::pair range(K from, K to) + { + if (from > to) + throw std::out_of_range("from is large than to"); + + Node *f = search(from); + Node *t = search(to); + + if (t && t->layer_[0]) + t = t->layer_[0]; + return std::make_pair(iterator { f }, iterator { t }); + } + + iterator begin() + { + return { header_->layer_[0] }; + } + + iterator end() + { + return { nullptr }; + } + + bool remove(K key) + { + Node *cur = header_; + Node *update[LEVEL + 1] { 0 }; + int i; + + for (i = cur_; i >= 0; i--) { + while (cur->layer_[i] && cur->layer_[i]->key_ < key) + cur = cur->layer_[i]; + update[i] = cur; + } + + cur = cur->layer_[0]; + if (cur && cur->key_ == key) { + // remove from each level + for (int i = 0; i <= cur_; i++) { + // this level has no cur + if (update[i]->layer_[i] != cur) + break; + update[i]->layer_[i] = cur->layer_[i]; + } + delete cur; + size_--; + // reduce cur level if current level has no element + while (cur_ > 0 && header_->layer_[cur_] == 0) + cur_--; + return true; + } + return false; + } + + size_t size() + { + return size_; + } + +private: + int cur_; + size_t size_; + Node *header_; + + static int gen_random_level() + { + int k = 1; + + while (rand() % 2) { + k++; + } + k = (k < LEVEL) ? k : LEVEL; + return k; + } + + // example: + // Level 0: 0x603000000040 1:2;0x6030000000d0 2:3;0x6030000000a0 3:4; + // Level 1: 0x603000000040 1:2;0x6030000000d0 2:3;0x6030000000a0 3:4; + // Level 2: 0x603000000040 1:2;0x6030000000a0 3:4; + // Level 3: 0x6030000000a0 3:4; + // Level 4: 0x6030000000a0 3:4; + // Level 5: 0x6030000000a0 3:4; <--- curr_level_ + // level 0 contains all nodes + static void cleanup(Node *head) + { + Node *next, *node = head->layer_[0]; + while (node) { + next = node->layer_[0]; + delete node; + node = next; + } + delete head; + } + + Node* search(K key) + { + Node *cur = header_; + + for (int i = cur_; i >= 0; --i) { + while (cur->layer_[i] && cur->layer_[i]->key_ < key) + cur = cur->layer_[i]; + } + if (cur) + cur = cur->layer_[0]; + return cur; + } +}; +} + +#endif // SKIPLIST_1653396693_H_