244 lines
5.5 KiB
C++
244 lines
5.5 KiB
C++
|
#ifndef MSKIPLIST_HEADER
|
||
|
#define MSKIPLIST_HEADER
|
||
|
|
||
|
#include <atomic>
|
||
|
#include <cassert>
|
||
|
#include <random>
|
||
|
#include <cstring>
|
||
|
|
||
|
template <typename T, typename P>
|
||
|
class SkipList {
|
||
|
public:
|
||
|
// 插入数据
|
||
|
void insert(const T& key, const P& value);
|
||
|
// 删除数据
|
||
|
void remove(const T& key);
|
||
|
// 查询数据
|
||
|
bool search(const T& key, P& value);
|
||
|
// 是否包含某个数据
|
||
|
bool contains(const T& key);
|
||
|
// 当前表节点个数
|
||
|
std::size_t count() const;
|
||
|
// 清除表
|
||
|
void clear();
|
||
|
|
||
|
public:
|
||
|
SkipList(int max_level = 12);
|
||
|
~SkipList();
|
||
|
|
||
|
private:
|
||
|
struct SkipNode;
|
||
|
std::size_t count_{};
|
||
|
SkipNode** pre_{};
|
||
|
SkipNode* header_{};
|
||
|
const int max_level_{}; // 限定的最大高度
|
||
|
std::atomic_int cur_max_height_{}; // 当前使用的最大高度
|
||
|
std::random_device rd_{};
|
||
|
std::mt19937 gen_{};
|
||
|
std::uniform_int_distribution<int> dis_{};
|
||
|
|
||
|
private:
|
||
|
int random_level();
|
||
|
SkipNode* find_node(const T& key);
|
||
|
};
|
||
|
|
||
|
template <typename T, typename P>
|
||
|
SkipList<T, P>::~SkipList()
|
||
|
{
|
||
|
clear();
|
||
|
delete[] pre_;
|
||
|
delete header_;
|
||
|
}
|
||
|
|
||
|
template <typename T, typename P>
|
||
|
void SkipList<T, P>::clear()
|
||
|
{
|
||
|
SkipNode* start = header_->get_no_bar(0);
|
||
|
while (start) {
|
||
|
SkipNode* n = start;
|
||
|
start = start->get_no_bar(0);
|
||
|
delete n;
|
||
|
--count_;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
template <typename T, typename P>
|
||
|
inline int SkipList<T, P>::random_level()
|
||
|
{
|
||
|
static const int base_ = 2;
|
||
|
int height = 1;
|
||
|
while (height < max_level_ && (dis_(gen_) % base_) == 0) {
|
||
|
++height;
|
||
|
}
|
||
|
return height;
|
||
|
}
|
||
|
|
||
|
template <typename T, typename P>
|
||
|
struct SkipList<T, P>::SkipNode {
|
||
|
T key_{};
|
||
|
P value_{};
|
||
|
int level_{};
|
||
|
|
||
|
public:
|
||
|
explicit SkipNode(int level = 1) { alloc(level); }
|
||
|
~SkipNode() { release(); }
|
||
|
SkipNode(const T& key, const P& value, int level)
|
||
|
{
|
||
|
key_ = key;
|
||
|
value_ = value;
|
||
|
alloc(level);
|
||
|
}
|
||
|
void alloc(int max_level)
|
||
|
{
|
||
|
if (max_level < 1) {
|
||
|
return;
|
||
|
}
|
||
|
release();
|
||
|
next_ = new std::atomic<SkipNode*>[max_level] {};
|
||
|
}
|
||
|
void release() { delete[] next_; }
|
||
|
SkipNode* get(int n)
|
||
|
{
|
||
|
assert(n >= 0);
|
||
|
return next_[n].load(std::memory_order_acquire);
|
||
|
}
|
||
|
SkipNode* get_no_bar(int n)
|
||
|
{
|
||
|
assert(n >= 0);
|
||
|
return next_[n].load(std::memory_order_relaxed);
|
||
|
}
|
||
|
void set(int n, SkipNode* node)
|
||
|
{
|
||
|
assert(n >= 0);
|
||
|
next_[n].store(node, std::memory_order_release);
|
||
|
}
|
||
|
void set_no_bar(int n, SkipNode* node)
|
||
|
{
|
||
|
assert(n >= 0);
|
||
|
next_[n].store(node, std::memory_order_relaxed);
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
std::atomic<SkipNode*>* next_{};
|
||
|
};
|
||
|
|
||
|
template <typename T, typename P>
|
||
|
inline SkipList<T, P>::SkipList(int max_level)
|
||
|
: max_level_(max_level),
|
||
|
cur_max_height_(1),
|
||
|
gen_(rd_()),
|
||
|
dis_(0, std::numeric_limits<int>::max())
|
||
|
{
|
||
|
assert(max_level_ > 0);
|
||
|
header_ = new SkipNode(max_level_);
|
||
|
pre_ = new SkipNode*[max_level_];
|
||
|
}
|
||
|
|
||
|
template <typename T, typename P>
|
||
|
typename SkipList<T, P>::SkipNode* SkipList<T, P>::find_node(const T& key)
|
||
|
{
|
||
|
memset(pre_, 0x0, sizeof(SkipNode*) * max_level_);
|
||
|
SkipNode* x = header_;
|
||
|
int level = cur_max_height_.load() - 1;
|
||
|
while (true) {
|
||
|
SkipNode* next = x->get(level);
|
||
|
if (next && next->key_ < key) {
|
||
|
x = next;
|
||
|
} else {
|
||
|
pre_[level] = x;
|
||
|
if (level == 0) {
|
||
|
return next;
|
||
|
} else {
|
||
|
--level;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
template <typename T, typename P>
|
||
|
inline bool SkipList<T, P>::contains(const T& key)
|
||
|
{
|
||
|
SkipNode* x = find_node(key);
|
||
|
if (x && x->key_ == key) {
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
template <typename T, typename P>
|
||
|
inline std::size_t SkipList<T, P>::count() const
|
||
|
{
|
||
|
return count_;
|
||
|
}
|
||
|
|
||
|
template <typename T, typename P>
|
||
|
inline void SkipList<T, P>::insert(const T& key, const P& value)
|
||
|
{
|
||
|
SkipNode* x = find_node(key);
|
||
|
|
||
|
if (x && x->key_ == key) {
|
||
|
x->value_ = value;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
int height = random_level();
|
||
|
if (height > cur_max_height_) {
|
||
|
for (int i = cur_max_height_; i < height; ++i) {
|
||
|
pre_[i] = header_;
|
||
|
}
|
||
|
cur_max_height_.store(height, std::memory_order_relaxed);
|
||
|
}
|
||
|
x = new SkipNode(key, value, height);
|
||
|
for (int i = 0; i < height; ++i) {
|
||
|
x->set_no_bar(i, pre_[i]->get_no_bar(i));
|
||
|
pre_[i]->set(i, x);
|
||
|
}
|
||
|
++count_;
|
||
|
}
|
||
|
|
||
|
template <typename T, typename P>
|
||
|
inline void SkipList<T, P>::remove(const T& key)
|
||
|
{
|
||
|
memset(pre_, 0x0, sizeof(SkipNode*) * max_level_);
|
||
|
SkipNode* x = header_;
|
||
|
SkipNode* purpose = nullptr;
|
||
|
int level = cur_max_height_.load() - 1;
|
||
|
while (true) {
|
||
|
if (level < 0) {
|
||
|
break;
|
||
|
}
|
||
|
SkipNode* next = x->get(level);
|
||
|
if (!next) {
|
||
|
--level;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (next->key_ < key) {
|
||
|
x = next;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (next->key_ == key) {
|
||
|
SkipNode* nx = next->get_no_bar(level);
|
||
|
x->set_no_bar(level, nx);
|
||
|
purpose = next;
|
||
|
}
|
||
|
--level;
|
||
|
}
|
||
|
delete purpose;
|
||
|
--count_;
|
||
|
}
|
||
|
|
||
|
template <typename T, typename P>
|
||
|
inline bool SkipList<T, P>::search(const T& key, P& value)
|
||
|
{
|
||
|
SkipNode* x = find_node(key);
|
||
|
if (x && x->key_ == key) {
|
||
|
value = x->value_;
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
#endif
|