skip_list.h
#pragma once
#include <algorithm>
#include <cstdlib>
#include <iostream>
namespace util {
#ifdef DEBUG
template <class T> void print(T arg) { std::cout << arg << " "; }
template <typename... Args> 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 T> 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_; /* pointer to the next node */
size_t span_; /* nums of node to be skiped,exclude itself */
};
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_; /* pointer to the data */
skiplist_node *prev_; /* pointer to the prev node */
skip_node_level *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));
} /*a++*/
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));
} /*a++*/
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 <class T_>
friend std::ostream &operator<<(std::ostream &out, const skip_list<T_> &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 <class T> skip_list<T>::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 <class T> skip_list<T>::~skip_list() {
skiplist_node *x = header();
if (x != nullptr) {
while (x != nullptr) {
skiplist_node *next = x->level_[0].next_;
delete x;
x = next;
}
}
}
template <class T> void skip_list<T>::insert(reference data) {
DEBUG_PRINT("\n\n");
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(
"\t\t", 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("\t\t\t", "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(
"\t\t\t\t", 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 <class T> void skip_list<T>::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("\t\t", 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 <class T>
void skip_list<T>::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 <class T>
std::ostream &operator<<(std::ostream &out, const skip_list<T> &slst) {
if (slst.header() != nullptr) {
const typename skip_list<T>::skiplist_node *x = slst.header();
for (int i = slst.level() - 1; i >= 0; i--) {
const auto *node = x->level_ + i;
const typename skip_list<T>::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 <class T> skip_list<T>::sl_iterator::sl_iterator(sl_iterator &&sli) {
if (this != &sli) {
pointer_ = sli.pointer_;
sli.pointer_ = nullptr;
}
}
template <class T>
skip_list<T>::sl_iterator::sl_iterator(const sl_iterator &&sli) {
if (this != &sli) {
pointer_ = sli.pointer_;
}
}
template <class T>
skip_list<T>::sl_iterator::sl_iterator(const sl_iterator &sli) {
if (this != &sli) {
pointer_ = sli.pointer_;
}
}
template <class T>
typename skip_list<T>::iterator skip_list<T>::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 <cassert>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <ostream>
#include <vector>
using namespace std;
void TEST_SKIPLIST() {
util::skip_list<int> slst;
vector<int> 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 name\n");
exit(-1);
}
pid_t pid = get_pid(argv[1]);
if (pid <= 0) {
printf("input the correct process name\n");
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<int> slst;
vector<int> 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 pass\n");
}
void TEST_SKIPLIST_ITERATOR() {
util::skip_list<int> slst;
vector<int> 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 pass\n");
}
void TEST_SKIPLIST_FIND() {
util::skip_list<int> slst;
vector<int> 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 pass\n");
}
int main(int argc, char *argv[]) {
TEST_SKIPLIST(); /*人工判断*/
TEST_SKIPLIST_FIND();
TEST_SKIPLIST_ITERATOR();
TEST_SKIPLIST_OOM(argv);
return 0;
}