跳表C++实现(skip_list)

这个博客展示了跳表(Skip List)的数据结构实现,包括插入、删除和查找操作,并进行了性能测试。博客中详细解释了跳表节点的定义、迭代器的实现以及相关操作的内部逻辑。此外,还提供了内存使用情况的测试来验证其效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值