当前位置:   article > 正文

unordered_set和unordered_map模拟实现

unordered_set和unordered_map模拟实现

目录

1 哈希表实现

1.1 字符串处理

1.2 节点

1.3 迭代器

1.4 表

2 unordered_map

3 unordered_set


1 哈希表实现

        采用开散列哈希表,映射方法为除留余数法。

1.1 字符串处理

使用仿函数对字符串类型的值转换为可以取余的整数。

  1. template<class K>
  2. struct Hash
  3. {
  4. size_t operator()(const K& key)
  5. {
  6. return key;
  7. }
  8. };
  9. template<>
  10. struct Hash<std::string>
  11. {
  12. size_t operator()(const std::string& s)
  13. {
  14. size_t res = 0;
  15. for (auto c : s)
  16. {
  17. res *= 31;
  18. res += c;
  19. }
  20. return res;
  21. }
  22. };

1.2 节点

哈希桶中为链表,设置为一般的链表节点即可。

  1. template<class T>
  2. struct HashNode
  3. {
  4. HashNode(T data)
  5. :_data(data)
  6. , next(nullptr)
  7. {}
  8. T _data;
  9. HashNode* next;
  10. };

1.3 迭代器

        由于迭代器++中需要整个哈希表才能寻找到下一个迭代器位置,迭代器中不仅存了节点指针还有整个哈希表的指针。

        整个迭代器实现的难点就是operator++,整体大逻辑是当前节点的下一个位置不为空,下一个位置就是下一个节点。否则就要在哈希表中从当前数组下标找到下一个数组下标位置中不为空的位置,并且该位置的第一个节点就是下一个位置的节点。

  1. template<class K, class V, class KeyofT, class HashFunc = Hash<K>>
  2. class HashTable;
  3. template<class K, class V, class Ref, class Ptr, class KeyofT
  4. ,class HashFunc = Hash<K>>
  5. struct __HTIterator
  6. {
  7. typedef HashNode<V> Node;
  8. typedef __HTIterator<K, V, Ref, Ptr, KeyofT, HashFunc> Self;
  9. Node* _node;
  10. HashTable<K, V, KeyofT, HashFunc>* _pht;
  11. public:
  12. __HTIterator(Node* node, HashTable<K, V, KeyofT, HashFunc>* pht)
  13. :_node(node)
  14. ,_pht(pht)
  15. {}
  16. Ref operator*()
  17. {
  18. return _node->_data;
  19. }
  20. Ptr operator->()
  21. {
  22. return &_node->_data;
  23. }
  24. Self& operator++()
  25. {
  26. if (_node->next)//下一个节点不为空
  27. {
  28. _node = _node->next;
  29. }
  30. else
  31. {
  32. KeyofT kot;
  33. HashFunc hf;
  34. size_t index = hf(kot(_node->_data)) % _pht->_ht.size();
  35. ++index;
  36. while ( index< _pht->_ht.size() && _pht->_ht[index] == nullptr)
  37. {
  38. index++;
  39. }
  40. if (index == _pht->_ht.size())//走到最后也没找到
  41. _node = nullptr;
  42. else
  43. _node = _pht->_ht[index];
  44. return *this;
  45. }
  46. }
  47. bool operator!=(const Self& s)const
  48. {
  49. return _node != s._node;
  50. }
  51. bool operator==(const Self& s)const
  52. {
  53. return _node == s._node;
  54. }
  55. };

1.4 表

        构造和析构是典型的链表操作,只要知道哈希表中的每一个位置都存储着链表头,执行相应操作即可。begin是哈希表中第一个不为空位置的第一个节点构造的迭代器,end就简单使用nullptr构造迭代器。表中其他插入、删除等各个接口的实现就不予具体说明了。

  1. template<class K, class V,class KeyofT, class HashFunc = Hash<K>>
  2. class HashTable
  3. {
  4. typedef HashNode<V> Node;
  5. template<class K, class V, class Ref, class Ptr, class KeyOfT, class HashFunc>
  6. friend struct __HTIterator;
  7. typedef HashTable<K, V, KeyofT, HashFunc> Self;
  8. public:
  9. typedef __HTIterator<K, V, V&, V*, KeyofT, HashFunc> iterator;
  10. HashTable(){}//HashTable() = default;
  11. HashTable(const Self& HT)
  12. {
  13. _ht.resize(HT._ht.size());
  14. for (size_t i = 0; i < HT._ht.size(); i++)
  15. {
  16. Node* cur = HT._ht[i];
  17. while (cur)
  18. {
  19. Node* copy = new Node(cur->_data);
  20. copy->next = _ht[i];
  21. _ht[i] = copy;
  22. cur = cur->next;
  23. }
  24. }
  25. }
  26. Self& operator=(Self copy)
  27. {
  28. std::swap(_size, copy._size);
  29. _ht.swap(copy._ht);
  30. return *this;
  31. }
  32. ~HashTable()
  33. {
  34. for (size_t i = 0; i < _ht.size(); i++)
  35. {
  36. Node* cur = _ht[i];
  37. while (cur)
  38. {
  39. Node* next = cur->next;
  40. delete cur;
  41. cur = next;
  42. }
  43. _ht[i] = nullptr;
  44. }
  45. }
  46. iterator begin()
  47. {
  48. for (int i = 0; i < _ht.size(); i++)
  49. {
  50. if (_ht[i])
  51. {
  52. return iterator(_ht[i],this);
  53. }
  54. }
  55. return end();
  56. }
  57. iterator end()
  58. {
  59. return iterator(nullptr, this);
  60. }
  61. // 插入
  62. std::pair<iterator,bool> Insert(const V& data)
  63. {
  64. KeyofT kot;
  65. iterator ret = Find(kot(data));
  66. if (ret!=end())
  67. {
  68. return std::make_pair(ret,false);
  69. }
  70. if (_ht.size() == _size)//负载因子到1
  71. {
  72. //扩容
  73. int newsize = _ht.size() == 0 ? 10 : _ht.size() * 2;
  74. std::vector<Node*> newTable;
  75. newTable.resize(newsize);
  76. //重新装入
  77. for (int i = 0; i < _ht.size(); i++)
  78. {
  79. Node* cur = _ht[i];
  80. while (cur)
  81. {
  82. Node* next = cur->next;
  83. Hash<K> hs;
  84. size_t index = hs(kot(_ht[i]->_data))
  85. % newTable.size();
  86. cur->next = newTable[index];
  87. newTable[index] = cur;
  88. cur = next;
  89. }
  90. _ht[i] = nullptr;
  91. }
  92. _ht.swap(newTable);
  93. }
  94. Hash<K> hs;
  95. size_t index = hs(kot(data)) % _ht.size();
  96. Node* newNode = new Node(data);
  97. newNode->next = _ht[index];
  98. _ht[index] = newNode;
  99. ++_size;
  100. return std::make_pair(iterator(newNode,this), false);
  101. }
  102. // 查找
  103. iterator Find(const K& key)
  104. {
  105. if (_ht.empty())
  106. return end();
  107. Hash<K> hs;
  108. size_t index = hs(key) % _ht.size();
  109. Node* cur = _ht[index];
  110. while (cur)
  111. {
  112. KeyofT kot;
  113. if (kot(cur->_data) == key)
  114. return iterator(cur,this);
  115. cur = cur->next;
  116. }
  117. return end();
  118. }
  119. // 删除
  120. bool Erase(const K& key)
  121. {
  122. if (_ht.empty())
  123. return false;
  124. Hash<K> hs;
  125. size_t index = hs(key) % _ht.size();
  126. Node* cur = _ht[index];
  127. Node* pre = nullptr;
  128. while (cur)
  129. {
  130. KeyofT kot;
  131. if (kot(cur->data) == key)
  132. {
  133. if (pre == nullptr)//头删
  134. _ht[index] = cur->next;
  135. else
  136. pre->next = cur->next;
  137. delete cur;
  138. --_size;
  139. return true;
  140. }
  141. pre = cur;
  142. cur = cur->next;
  143. }
  144. return false;
  145. }
  146. size_t Size()const
  147. {
  148. return _size;
  149. }
  150. bool Empty() const
  151. {
  152. return _size == 0;
  153. }
  154. private:
  155. std::vector<Node*> _ht;
  156. size_t _size = 0;//有效数据的个数
  157. };
  158. }

2 unordered_map

        按要求完成仿函数,由于map传入的是键值对,在下一层的表中只需要取键即可。operator[]在map中也是这么实现的,利用插入函数中就包含了查找的特性,调用插入函数,获得返回值的内容即可完成[]的重载。

  1. #pragma once
  2. #include "Open_Hash.h"
  3. using namespace Open_Hash;
  4. namespace lwh
  5. {
  6. template<class K, class V, class HashFunc = Hash<K>>
  7. class unordered_map
  8. {
  9. struct MapKeyOfT
  10. {
  11. const K& operator()(const std::pair<K,V>& kv)
  12. {
  13. return kv.first;
  14. }
  15. };
  16. public:
  17. typedef typename HashTable<K, std::pair<K,V>, MapKeyOfT, HashFunc>::iterator iterator;
  18. iterator begin()
  19. {
  20. return _HT.begin();
  21. }
  22. iterator end()
  23. {
  24. return _HT.end();
  25. }
  26. std::pair<iterator,bool> insert(const std::pair<K, V> kv)
  27. {
  28. return _HT.Insert(kv);
  29. }
  30. V& operator[](const K& key)
  31. {
  32. return _HT.Insert(make_pair(key, V())).first->second;
  33. }
  34. private:
  35. HashTable<K, std::pair<K,V>, MapKeyOfT, HashFunc> _HT;
  36. };
  37. }

3 unordered_set

  1. #pragma once
  2. #include "Open_Hash.h"
  3. using namespace Open_Hash;
  4. namespace lwh
  5. {
  6. template<class K, class HashFunc = Hash<K>>
  7. class unordered_set
  8. {
  9. struct SetKeyOfT
  10. {
  11. const K& operator()(const K& key)
  12. {
  13. return key;
  14. }
  15. };
  16. public:
  17. typedef typename HashTable<K, K, SetKeyOfT, HashFunc>::iterator iterator;
  18. iterator begin()
  19. {
  20. return _HT.begin();
  21. }
  22. iterator end()
  23. {
  24. return _HT.end();
  25. }
  26. std::pair<iterator, bool> insert(const K key)
  27. {
  28. return _HT.Insert(key);
  29. }
  30. private:
  31. HashTable<K,K, SetKeyOfT, HashFunc> _HT;
  32. };
  33. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/人工智能uu/article/detail/933031
推荐阅读
相关标签
  

闽ICP备14008679号