经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C++ » 查看文章
C++跳表项目源码分析
来源:cnblogs  作者:零十  时间:2021/5/17 9:26:24  对本文有异议

什么是跳表skiplist

一种基于链表list改造的数据结构,以空间换时间的方式加速链表的搜索。
具体定义这里不赘述,具体可看传送门:漫画小灰之跳表

本文主要赏析github上一个跳表项目的实现
传送门:一个使用C++编程实现的基于跳表的轻量级键值型数据库

项目中跳表实现都在一个头文件skipList.h中,main.cpp为使用示例。

skiplist源码分析

节点类定义

节点为key-value型,由于跳表为多层结构,数组forward用于存放每层中该节点的下一节点

  1. class Node {
  2. public:
  3. Node() {}
  4. Node(K k, V v, int);
  5. ~Node();
  6. K get_key() const;
  7. V get_value() const;
  8. void set_value(V);
  9. // Linear array to hold pointers to next node of different level
  10. //存放不同层中下一个节点的指针的线性表
  11. Node<K, V> **forward;
  12. int node_level;
  13. private:
  14. K key;
  15. V value;
  16. };

节点构造函数
level为该节点在跳表中有多少层,创建节点时随机分配

  1. template<typename K, typename V>
  2. Node<K, V>::Node(const K k, const V v, int level) {
  3. this->key = k;
  4. this->value = v;
  5. this->node_level = level;
  6. // level + 1, because array index is from 0 - level
  7. this->forward = new Node<K, V>*[level+1];
  8. // Fill forward array with 0(NULL)
  9. memset(this->forward, 0, sizeof(Node<K, V>*)*(level+1));
  10. };

跳表类定义

我们主要看创建节点、插入节点、搜索元素、删除元素这几个方法的实现。

  1. // Class template for Skip list
  2. template <typename K, typename V>
  3. class SkipList {
  4. public:
  5. SkipList(int);
  6. ~SkipList();
  7. int get_random_level();
  8. Node<K, V>* create_node(K, V, int);
  9. int insert_element(K, V);
  10. void display_list();
  11. bool search_element(K);
  12. void delete_element(K);
  13. void dump_file();
  14. void load_file();
  15. int size();
  16. private:
  17. void get_key_value_from_string(const std::string& str, std::string* key, std::string* value);
  18. bool is_valid_string(const std::string& str);
  19. private:
  20. // Maximum level of the skip list
  21. //最大层数
  22. int _max_level;
  23. // current level of skip list
  24. //当前层数
  25. int _skip_list_level;
  26. // pointer to header node
  27. //头节点
  28. Node<K, V> *_header;
  29. // file operator
  30. std::ofstream _file_writer;
  31. std::ifstream _file_reader;
  32. // skiplist current element count
  33. int _element_count;
  34. };

构造函数
头节点的level为跳表的最大层数
项目中的析构函数应该是有内存泄漏的问题的,只detele了头节点

  1. // construct skip list
  2. template<typename K, typename V>
  3. SkipList<K, V>::SkipList(int max_level) {
  4. this->_max_level = max_level;
  5. this->_skip_list_level = 0;
  6. this->_element_count = 0;
  7. // create header node and initialize key and value to null
  8. K k;
  9. V v;
  10. this->_header = new Node<K, V>(k, v, _max_level);
  11. };

创建节点

直接new一个node,返回指针

  1. // create new node
  2. template<typename K, typename V>
  3. Node<K, V>* SkipList<K, V>::create_node(const K k, const V v, int level) {
  4. Node<K, V> *n = new Node<K, V>(k, v, level);
  5. return n;
  6. }

插入节点

  1. 如在以下跳表中插入key50的节点:
  2. +------------+
  3. | insert 50 |
  4. +------------+
  5. level 4 +-->1+ 100
  6. |
  7. | insert +----+
  8. level 3 1+-------->10+---------------> | 50 | 70 100
  9. | |
  10. | |
  11. level 2 1 10 30 | 50 | 70 100
  12. | |
  13. | |
  14. level 1 1 4 10 30 | 50 | 70 100
  15. | |
  16. | |
  17. level 0 1 4 9 10 30 40 | 50 | 60 70 100

需要在每层中找到插入的位置,即每层插入位置的上一个节点,该节点的key小于插入节点,下一节点的key大于插入节点。这里定义了一个数组update存放插入位置的上一个节点。

  1. template<typename K, typename V>
  2. int SkipList<K, V>::insert_element(const K key, const V value) {
  3. mtx.lock();
  4. Node<K, V> *current = this->_header;
  5. // create update array and initialize it
  6. // update is array which put node that the node->forward[i] should be operated later
  7. //update[i]是第i层中key最后一个比插入key小的node*
  8. Node<K, V> *update[_max_level+1];
  9. memset(update, 0, sizeof(Node<K, V>*)*(_max_level+1));
  10. // start form highest level of skip list
  11. //从最高层搜索填补update
  12. for(int i = _skip_list_level; i >= 0; i--) {
  13. while(current->forward[i] != NULL && current->forward[i]->get_key() < key) {
  14. current = current->forward[i];
  15. }
  16. update[i] = current;
  17. }
  18. //在上图示例中,如插入key 50, 在每层中,得到它的上一节点的key依次为40,30,30,10,1
  19. // reached level 0 and forward pointer to right node, which is desired to insert key.
  20. //第0层, current->forward[0]为应该插入的位置
  21. current = current->forward[0];
  22. // if current node have key equal to searched key, we get it
  23. //该key已存在,解锁后直接返回
  24. if (current != NULL && current->get_key() == key) {
  25. std::cout << "key: " << key << ", exists" << std::endl;
  26. mtx.unlock();
  27. return 1;
  28. }
  29. // if current is NULL that means we have reached to end of the level
  30. //current为空,表示到达了该层的末尾
  31. // if current's key is not equal to key that means we have to insert node between update[0] and current node
  32. //不为空则要在update[0]和current之间插入
  33. if (current == NULL || current->get_key() != key ) {
  34. // Generate a random level for node
  35. //随机层数
  36. int random_level = get_random_level();
  37. // If random level is greater thar skip list's current level, initialize update value with pointer to header
  38. //随机层数比当前的层数高时,比当前层高的层前一节点就是_header
  39. if (random_level > _skip_list_level) {
  40. for (int i = _skip_list_level+1; i < random_level+1; i++) {
  41. update[i] = _header;
  42. }
  43. _skip_list_level = random_level;
  44. }
  45. // create new node with random level generated
  46. //创建节点
  47. Node<K, V>* inserted_node = create_node(key, value, random_level);
  48. // insert node
  49. // 插入节点
  50. //1、对每一层,插入节点的下一节点为update[i]的下一节点
  51. //2、update[i]的下一节点更新为插入节点
  52. for (int i = 0; i <= random_level; i++) {
  53. inserted_node->forward[i] = update[i]->forward[i];
  54. update[i]->forward[i] = inserted_node;
  55. }
  56. std::cout << "Successfully inserted key:" << key << ", value:" << value << std::endl;
  57. _element_count ++; //增加节点数
  58. }
  59. mtx.unlock();
  60. return 0;
  61. }

搜索节点

  1. +------------+
  2. | select 60 |
  3. +------------+
  4. level 4 +-->1+ 100
  5. |
  6. |
  7. level 3 1+-------->10+------------------>50+ 70 100
  8. |
  9. |
  10. level 2 1 10 30 50| 70 100
  11. |
  12. |
  13. level 1 1 4 10 30 50| 70 100
  14. |
  15. |
  16. level 0 1 4 9 10 30 40 50+-->60 70 100

从顶层的header开始,从上而下,从左到右,依次遍历每层的节点key,直到第0层。

  1. template<typename K, typename V>
  2. bool SkipList<K, V>::search_element(K key) {
  3. std::cout << "search_element-----------------" << std::endl;
  4. Node<K, V> *current = _header;
  5. // start from highest level of skip list
  6. for (int i = _skip_list_level; i >= 0; i--) {
  7. while (current->forward[i] && current->forward[i]->get_key() < key) {
  8. current = current->forward[i];
  9. }
  10. }
  11. //reached level 0 and advance pointer to right node, which we search
  12. current = current->forward[0];
  13. // if current node have key equal to searched key, we get it
  14. //key存在则找到目标元素
  15. if (current and current->get_key() == key) {
  16. std::cout << "Found key: " << key << ", value: " << current->get_value() << std::endl;
  17. return true;
  18. }
  19. std::cout << "Not Found Key:" << key << std::endl;
  20. return false;
  21. }

删除节点

同理,先找到每层中该节点位置的前一节点
若某层中该key存在,前一节点的下一节点指向该元素的下一节点。

  1. // Delete element from skip list
  2. template<typename K, typename V>
  3. void SkipList<K, V>::delete_element(K key) {
  4. mtx.lock();
  5. Node<K, V> *current = this->_header;
  6. Node<K, V> *update[_max_level+1];
  7. memset(update, 0, sizeof(Node<K, V>*)*(_max_level+1));
  8. // start from highest level of skip list
  9. for (int i = _skip_list_level; i >= 0; i--) {
  10. while (current->forward[i] !=NULL && current->forward[i]->get_key() < key) {
  11. current = current->forward[i];
  12. }
  13. update[i] = current;
  14. }
  15. current = current->forward[0];
  16. //找到该节点
  17. if (current != NULL && current->get_key() == key) {
  18. // start for lowest level and delete the current node of each level
  19. for (int i = 0; i <= _skip_list_level; i++) {
  20. // if at level i, next node is not target node, break the loop.
  21. //如果该层没有该节点,跳过
  22. if (update[i]->forward[i] != current)
  23. break;
  24. update[i]->forward[i] = current->forward[i];
  25. }
  26. // Remove levels which have no elements
  27. //如果删除节点后该层没有元素,则调整当前的层数
  28. while (_skip_list_level > 0 && _header->forward[_skip_list_level] == 0) {
  29. _skip_list_level --;
  30. }
  31. std::cout << "Successfully deleted key "<< key << std::endl;
  32. _element_count --;
  33. delete current; //这句我自己加的,源码中没有,难道节点只new不delete吗?
  34. }
  35. mtx.unlock();
  36. return;
  37. }

原文链接:http://www.cnblogs.com/Lj-ming/p/14755791.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号