skip_list.h
#pragma once #include #include#include namespace util { #ifdef DEBUG template void print(T arg) { std::cout << arg << " "; } template void debug_print(Args... args) { int arr[] = {(print(args), 0)...}; } #define DEBUG_PRINT(...) debug_print(__FUNCTION__, ":", __LINE__, ##__VA_ARGS__); #else #define DEBUG_PRINT(...) #endif #define SKIPLIST_MAXLEVEL 4 template class skip_list { using value_type = T; using pointer = value_type *; using const_pointer = const value_type *; using reference = value_type &; using const_reference = const value_type &; using size_t = unsigned long long; class skiplist_node { class skip_node_level { public: skip_node_level() : next_(nullptr), span_(0) {} ~skip_node_level() { next_ = nullptr; } skiplist_node *next_; size_t span_; }; public: skiplist_node(int level, pointer data) : data_(data), prev_(nullptr), level_(new skip_node_level[level]) {} ~skiplist_node() { delete[] level_; level_ = nullptr; prev_ = nullptr; } pointer data_; skiplist_node *prev_; skip_node_level *level_; }; class sl_iterator { public: explicit sl_iterator(skiplist_node *node) : pointer_(node) {} sl_iterator(sl_iterator &&sli); inline friend bool operator==(const sl_iterator &lhs, const sl_iterator &rhs) { return lhs.pointer_ == rhs.pointer_; } inline friend bool operator!=(const sl_iterator &lhs, const sl_iterator &rhs) { return lhs.pointer_ != rhs.pointer_; } sl_iterator &operator=(sl_iterator &&sli) { if (this != &sli) { pointer_ = sli.pointer_; sli.pointer_ = nullptr; } return *this; } sl_iterator(const sl_iterator &&sli); sl_iterator &operator=(sl_iterator &sli) { if (this != &sli) { pointer_ = sli.pointer_; } return *this; } sl_iterator(const sl_iterator &sli); sl_iterator &operator=(const sl_iterator &&sli) { if (this != &sli) { pointer_ = sli.pointer_; } return *this; } inline sl_iterator &operator++() { pointer_ = pointer_->level_[0].next_; return *this; } inline sl_iterator operator++(int) { skiplist_node *tmp = pointer_; pointer_ = pointer_->level_[0].next_; return std::move(sl_iterator(tmp)); } inline sl_iterator &operator--() { pointer_ = pointer_->prev_; return *this; } inline sl_iterator operator--(int) { skiplist_node *tmp = pointer_; pointer_ = pointer_->prev_; return std::move(sl_iterator(tmp)); } inline reference operator()() { return *pointer_->data_; } inline const_reference operator()() const { return *pointer_->data_; } inline reference operator*() { return *pointer_->data_; } inline const_reference operator*() const { return *pointer_->data_; } private: skiplist_node *pointer_; }; using iterator = sl_iterator; public: skip_list(); ~skip_list(); void insert(reference data); void remove(const_reference data); template friend std::ostream &operator<<(std::ostream &out, const skip_list &slst); iterator begin() { return std::move(iterator(header_->level_[0].next_)); } iterator back() { return std::move(iterator(tailer_)); } iterator end() { return std::move(iterator(nullptr)); } inline int level(bool do_latch = false) const { return level_; } inline size_t length(bool do_latch = false) const { return length_; } iterator find(const_reference data); private: void remove_helper(skiplist_node *x, skiplist_node **update); static inline int random_level() { return random() % SKIPLIST_MAXLEVEL + 1; } inline void set_level(int level, bool do_latch = false) { level_ = level; } inline void level_deacur(bool do_latch = false) { --level_; } inline void set_length(size_t length, bool do_latch = false) { length_ = length; } inline void length_incr(bool do_latch = false) { ++length_; } inline void length_deacur(bool do_latch = false) { --length_; } inline skiplist_node *header(bool do_latch = false) const { return header_; } inline void set_header(skiplist_node *header, bool do_latch = false) const { return header_; } inline skiplist_node *tail(bool do_latch = false) const { return tailer_; } inline void set_tail(skiplist_node *tail, bool do_latch = false) { tailer_ = tail; } private: skiplist_node *header_, *tailer_; size_t length_; int level_; }; } // namespace util #include "skip_list.inc"
skip_list.inc
namespace util {
template skip_list::skip_list() {
int j;
level_ = 1;
length_ = 0;
header_ = new skiplist_node(SKIPLIST_MAXLEVEL, nullptr);
tailer_ = nullptr;
for (j = 0; j < SKIPLIST_MAXLEVEL; j++) {
header_->level_[j].next_ = tailer_;
header_->level_[j].span_ = 0;
}
header_->prev_ = nullptr;
}
template skip_list::~skip_list() {
skiplist_node *x = header();
if (x != nullptr) {
while (x != nullptr) {
skiplist_node *next = x->level_[0].next_;
delete x;
x = next;
}
}
}
template void skip_list::insert(reference data) {
DEBUG_PRINT("nn");
skiplist_node *update[SKIPLIST_MAXLEVEL], *x;
unsigned int rank[SKIPLIST_MAXLEVEL];
int i, nlevel;
x = header();
for (i = level() - 1; i >= 0; --i) {
rank[i] = ((i == level() - 1) ? 0 : rank[i + 1]);
DEBUG_PRINT(i, rank[i], "n");
DEBUG_PRINT(x, "n")
while (x->level_[i].next_ != nullptr &&
*x->level_[i].next_->data_ <= data) {
rank[i] += x->level_[i].span_;
DEBUG_PRINT(x, "n")
x = x->level_[i].next_;
}
update[i] = x;
DEBUG_PRINT(
"tt", i, "prev",
(x != nullptr ? (x->data_ != nullptr ? *x->data_ : -1) : -3), "next",
(x->level_[i].next_ != nullptr ? (x->level_[i].next_->data_ != nullptr
? *x->level_[i].next_->data_
: -1)
: -3),
data, "n");
}
nlevel = random_level();
DEBUG_PRINT("ttt", "nlevel", nlevel, "n");
if (nlevel > level()) {
for (i = level(); i < nlevel; i++) {
rank[i] = 0;
update[i] = header();
update[i]->level_[i].span_ = length();
}
set_level(nlevel);
}
x = new skiplist_node(nlevel, &data);
DEBUG_PRINT("data", x, *x->data_, "n")
DEBUG_PRINT(
"data",
x->prev_ != nullptr && x->prev_->data_ != nullptr ? *x->data_ : -3, "n")
for (i = 0; i < nlevel; ++i) {
x->level_[i].next_ = update[i]->level_[i].next_;
update[i]->level_[i].next_ = x;
DEBUG_PRINT(
"tttt", update[i],
update[i]->data_ != nullptr ? *update[i]->data_ : -3, *x->data_,
(x->level_[i].next_ != nullptr && x->level_[i].next_->data_ != nullptr
? *x->level_[i].next_->data_
: -3),
"n");
x->level_[i].span_ = update[i]->level_[i].span_ - (rank[0] - rank[i]);
update[i]->level_[i].span_ = (rank[0] - rank[i]) + 1;
}
for (i = nlevel; i < level(); ++i) {
update[i]->level_[i].span_++;
}
x->prev_ = (update[0] == header()) ? nullptr : update[0];
if (x->level_[0].next_ != nullptr) {
x->level_[0].next_->prev_ = x;
} else {
set_tail(x);
}
length_incr();
}
template void skip_list::remove(const_reference data) {
skiplist_node *update[SKIPLIST_MAXLEVEL];
skiplist_node *x = header();
for (int i = level() - 1; i >= 0; --i) {
DEBUG_PRINT(x, "n")
while (x->level_[i].next_ != nullptr &&
*x->level_[i].next_->data_ < data) {
DEBUG_PRINT(x, "n")
x = x->level_[i].next_;
}
update[i] = x;
if (i == 0 && (x->level_[i].next_ == nullptr ||
x->level_[i].next_->data_ == nullptr ||
*x->level_[i].next_->data_ != data)) {
return;
} else if (i == 0) {
x = x->level_[0].next_;
break;
}
DEBUG_PRINT("tt", i, "prev",
(update[i] != nullptr
? (update[i]->data_ != nullptr ? *update[i]->data_ : -1)
: -3),
"target",
(x != nullptr ? (x->data_ != nullptr ? *x->data_ : -1) : -3),
data, "n");
}
remove_helper(x, update);
}
template
void skip_list::remove_helper(skiplist_node *x, skiplist_node **update) {
int i;
for (i = 0; i < level(); i++) {
if (update[i]->level_[i].next_ == x) {
update[i]->level_[i].span_ += x->level_[i].span_ - 1;
update[i]->level_[i].next_ = x->level_[i].next_;
} else {
update[i]->level_[i].span_ -= 1;
}
}
if (x->level_[0].next_) {
x->level_[0].next_->prev_ = x->prev_;
} else {
set_tail(x->prev_);
}
while (level() > 1 && header()->level_[level() - 1].next_ == nullptr) {
length_deacur();
level_deacur();
}
}
template
std::ostream &operator<<(std::ostream &out, const skip_list &slst) {
if (slst.header() != nullptr) {
const typename skip_list::skiplist_node *x = slst.header();
for (int i = slst.level() - 1; i >= 0; i--) {
const auto *node = x->level_ + i;
const typename skip_list::skiplist_node *iter = node->next_;
while (iter != nullptr) {
T *data = iter->data_;
if (data != nullptr) {
out << "[" << *data << "," << iter->level_[i].span_ << "]"
<< "->";
} else {
out << "nullptr->";
}
iter = iter->level_[i].next_;
}
out << "nullptr" << std::endl;
}
}
}
template skip_list::sl_iterator::sl_iterator(sl_iterator &&sli) {
if (this != &sli) {
pointer_ = sli.pointer_;
sli.pointer_ = nullptr;
}
}
template
skip_list::sl_iterator::sl_iterator(const sl_iterator &&sli) {
if (this != &sli) {
pointer_ = sli.pointer_;
}
}
template
skip_list::sl_iterator::sl_iterator(const sl_iterator &sli) {
if (this != &sli) {
pointer_ = sli.pointer_;
}
}
template
typename skip_list::iterator skip_list::find(const_reference data) {
skiplist_node *x = header();
for (int i = level() - 1; i >= 0; --i) {
DEBUG_PRINT(x, "n")
while (x->level_[i].next_ != nullptr && *x->level_[i].next_->data_ < data) {
DEBUG_PRINT(x, "n")
x = x->level_[i].next_;
}
if (x->level_[i].next_ != nullptr && *x->level_[i].next_->data_ == data) {
return std::move(iterator(x->level_[i].next_));
}
}
return end();
}
} // namespace util
TEST
#include "operation/stats.h" #include "skip_list.h" #include#include #include #include #include #include using namespace std; void TEST_SKIPLIST() { util::skip_list slst; vector vec; vec.reserve(20); for (int i = 0; i < 20; i++) { vec.push_back((int)(random() % 1001)); } for(int i = 0;i < 20;i++){ slst.insert(vec[i]); } std::cout << slst << std::endl; slst.remove(5); std::cout << slst << std::endl; slst.remove(10); std::cout << slst << std::endl; slst.remove(0); std::cout << slst << std::endl; } void TEST_SKIPLIST_OOM(char *argv[]) { if (argv[1] == nullptr) { printf("input the correct process namen"); exit(-1); } pid_t pid = get_pid(argv[1]); if (pid <= 0) { printf("input the correct process namen"); exit(-1); } unsigned int mem_use = 0, pre_mem_use = 0; int loops = 100; for (int i = 0; i < loops; i++) { if (i == 0) { pre_mem_use = get_proc_mem(pid); mem_use = max(pre_mem_use, mem_use); } mem_use = max(get_proc_mem(pid), mem_use); util::skip_list slst; vector vec; vec.reserve(10000); for (int i = 0; i < 10000; i++) { vec.push_back(i); slst.insert(vec[i]); } slst.remove(5); slst.remove(10); slst.remove(0); } assert(mem_use < pre_mem_use * 4); printf("OOM test passn"); } void TEST_SKIPLIST_ITERATOR() { util::skip_list slst; vector vec; vec.reserve(10); for (int i = 0; i < 10; i++) { vec.push_back(i); slst.insert(vec[i]); } bool debug_flag1 = slst.begin() == slst.end(); int i = 0; int pre_value = *slst.begin(); for (auto iter = slst.begin(); iter != slst.end() && i < vec.size(); iter++, i++) { assert(*iter == vec[i] && pre_value <= *iter); pre_value = *iter; } i = vec.size() - 1; for (auto iter = slst.back(); iter != slst.end() && i >= 0; iter--, i--) { assert(*iter == vec[i]); } printf("iterator test passn"); } void TEST_SKIPLIST_FIND() { util::skip_list slst; vector vec; vec.reserve(10); for (int i = 0; i < 10; i++) { vec.push_back(i); slst.insert(vec[i]); } assert(slst.find(5) != slst.end() && *slst.find(5) == 5); assert(slst.find(11) == slst.end()); assert(slst.find(-4) == slst.end()); printf("find test passn"); } int main(int argc, char *argv[]) { TEST_SKIPLIST(); TEST_SKIPLIST_FIND(); TEST_SKIPLIST_ITERATOR(); TEST_SKIPLIST_OOM(argv); return 0; }



