当前位置:   article > 正文

unordered_map和set

unordered_map和set

前言:本篇文章继续分享新的容器unordered_map和set。前边我们分享过map和set,其底层为红黑树,而unordered_map和set的底层则为哈希表,因此在unordered_map和set的实现中,我们可以效仿许多在map和set的中就分享过的一些知识,所以在本篇文章中,就不对分享过的知识进行重复讲解。

而unordered_map和set与map和set的区别,即为红黑树和哈希表的区别


目录

一.修改hash

二.迭代器

三.完整代码

1.unordered_map

2.unordered_set

四.总结


一.修改hash

我们所实现的普通哈希表肯定是无法直接拿来作为unordered_map和set的底层代码的,所以我们需要对其进行优化修改,完整代码如下:

  1. template<class K>
  2. struct HashFunc
  3. {
  4. size_t operator()(const K& key)
  5. {
  6. return (size_t)key;
  7. }
  8. };
  9. struct HashStringFunc
  10. {
  11. size_t operator()(const string& s)
  12. {
  13. size_t hash = 0;
  14. for (auto e : s)
  15. {
  16. hash += e;
  17. }
  18. return hash;
  19. }
  20. };
  21. namespace hash_bucket
  22. {
  23. template<class T>
  24. struct HashNode
  25. {
  26. T _data;
  27. HashNode<T>* _next;
  28. HashNode(const T& data)
  29. :_data(data)
  30. , _next(nullptr)
  31. {}
  32. };
  33. //前置声明
  34. template<class K, class T, class KeyOfT, class Hash>
  35. class HashTable;
  36. template<class K, class T, class KeyOfT, class Hash>
  37. struct __Iterator
  38. {
  39. typedef HashNode<T> Node;
  40. typedef __Iterator<K, T, KeyOfT, Hash> Self;
  41. Node* _node;
  42. HashTable<K, T, KeyOfT, Hash>* _pht;
  43. __Iterator(Node* node, HashTable<K, T, KeyOfT, Hash>* pht)
  44. :_node(node)
  45. ,_pht(pht)
  46. {}
  47. T& operator*()
  48. {
  49. return _node->_data;
  50. }
  51. T* operator->()
  52. {
  53. return &_node->_data;
  54. }
  55. Self& operator++()
  56. {
  57. if (_node->_next)
  58. //当前桶没走完,找到下一个节点
  59. _node = _node->_next;
  60. else
  61. {
  62. //当前桶走完了,找下一个不为空的桶的第一个节点
  63. KeyOfT kot;
  64. Hash hs;
  65. size_t i = hs(kot(_node->_data)) % _pht->_tables.size();
  66. i++;
  67. for (; i < _pht->_tables.size(); i++)
  68. {
  69. if (_pht->_tables[i])
  70. break;
  71. }
  72. if (i == _pht->_tables.size())
  73. //所有桶都走完了,置nullptr
  74. _node = nullptr;
  75. else
  76. _node = _pht->_tables[i];
  77. }
  78. return *this;
  79. }
  80. bool operator!=(const Self& s)
  81. {
  82. return _node != s._node;
  83. }
  84. };
  85. template<class K, class T, class KeyOfT, class Hash>
  86. class HashTable
  87. {
  88. typedef HashNode<T> Node;
  89. public:
  90. //友元
  91. template<class K, class T, class KeyOfT, class Hash>
  92. friend struct __Iterator;
  93. typedef __Iterator<K, T, KeyOfT, Hash> iterator;
  94. iterator begin()
  95. {
  96. for (size_t i = 0; i < _tables.size(); i++)
  97. {
  98. Node* cur = _tables[i];
  99. if (cur)
  100. {
  101. return iterator(cur, this);
  102. }
  103. }
  104. return end();
  105. }
  106. iterator end()
  107. {
  108. return iterator(nullptr, this);
  109. }
  110. HashTable()
  111. {
  112. _tables.resize(10, nullptr);
  113. _n = 0;
  114. }
  115. ~HashTable()
  116. {
  117. for (size_t i = 0; i < _tables.size(); i++)
  118. {
  119. Node* cur = _tables[i];
  120. while (cur)
  121. {
  122. Node* next = cur->_next;
  123. delete cur;
  124. cur = next;
  125. }
  126. _tables[i] = nullptr;
  127. }
  128. }
  129. //插入
  130. pair<iterator,bool> Insert(const T& data)
  131. {
  132. KeyOfT kot;
  133. Hash hs;
  134. //判断是否存在
  135. iterator it = Find(kot(data));
  136. if (it != end())
  137. return make_pair(it,false);
  138. //扩容
  139. if (_n == _tables.size())
  140. {
  141. vector<Node*> newtables(_tables.size() * 2, nullptr);
  142. for (size_t i = 0; i < _tables.size(); i++)
  143. {
  144. Node* cur = _tables[i];
  145. while (cur)
  146. {
  147. Node* next = cur->_next;
  148. size_t hashi = hs(kot(cur->_data)) % newtables.size();
  149. cur->_next = newtables[hashi];
  150. newtables[hashi] = cur;
  151. cur = next;
  152. }
  153. _tables[i] = nullptr;
  154. }
  155. _tables.swap(newtables);
  156. }
  157. size_t hashi = hs(kot(data)) % _tables.size();
  158. Node* newnode = new Node(data);
  159. //头插
  160. newnode->_next = _tables[hashi];
  161. _tables[hashi] = newnode;
  162. ++_n;
  163. return make_pair(iterator(newnode,this), false);
  164. }
  165. //寻找
  166. iterator Find(const K& key)
  167. {
  168. KeyOfT kot;
  169. Hash hs;
  170. size_t hashi = hs(key) % _tables.size();
  171. Node* cur = _tables[hashi];
  172. while (cur)
  173. {
  174. if (kot(cur->_data) == key)
  175. return iterator(cur,this);
  176. cur = cur->_next;
  177. }
  178. return end();
  179. }
  180. bool Erase(const K& key)
  181. {
  182. KeyOfT kot;
  183. Hash hs;
  184. size_t hashi = hs(key) % _tables.size();
  185. Node* cur = _tables[hashi];
  186. Node* prev = nullptr;
  187. while (cur)
  188. {
  189. if (kot(cur->_data) == key)
  190. {
  191. //删除的是第一个节点
  192. if (prev == nullptr)
  193. {
  194. _tables[hashi] = cur->_next;
  195. }
  196. else
  197. {
  198. prev->_next = cur->_next;
  199. }
  200. delete cur;
  201. }
  202. else
  203. {
  204. prev = cur;
  205. cur = cur->_next;
  206. }
  207. }
  208. return false;
  209. }
  210. private:
  211. vector<Node*> _tables;//指针数组
  212. size_t _n;
  213. };
  214. }

这其中包括只对key进行操作的修改,以及当插入的元素为string型时对其进行的特殊处理。都是我们之前所分享过的知识。下面我们重点来看迭代器


二.迭代器

先来看整体结构:

  1. template<class K, class T, class KeyOfT, class Hash>
  2. struct __Iterator
  3. {
  4. typedef HashNode<T> Node;
  5. typedef __Iterator<K, T, KeyOfT, Hash> Self;
  6. Node* _node;
  7. HashTable<K, T, KeyOfT, Hash>* _pht;
  8. __Iterator(Node* node, HashTable<K, T, KeyOfT, Hash>* pht)
  9. :_node(node)
  10. ,_pht(pht)
  11. {}
  12. T& operator*()
  13. {
  14. return _node->_data;
  15. }
  16. T* operator->()
  17. {
  18. return &_node->_data;
  19. }
  20. Self& operator++()
  21. {
  22. if (_node->_next)
  23. //当前桶没走完,找到下一个节点
  24. _node = _node->_next;
  25. else
  26. {
  27. //当前桶走完了,找下一个不为空的桶的第一个节点
  28. KeyOfT kot;
  29. Hash hs;
  30. size_t i = hs(kot(_node->_data)) % _pht->_tables.size();
  31. i++;
  32. for (; i < _pht->_tables.size(); i++)
  33. {
  34. if (_pht->_tables[i])
  35. break;
  36. }
  37. if (i == _pht->_tables.size())
  38. //所有桶都走完了,置nullptr
  39. _node = nullptr;
  40. else
  41. _node = _pht->_tables[i];
  42. }
  43. return *this;
  44. }
  45. bool operator!=(const Self& s)
  46. {
  47. return _node != s._node;
  48. }
  49. };

其中最为重要的莫过于++运算符的重载,因为我们的哈希表是闭散列的哈希桶,所以是以指针数组作为底层。

在执行++操作时,需要先判断当前节点的next是否存在,存在就直接为next节点,不存在就说明当前节点已经是其所属的桶里的最后一个节点,那么接下来的操作就是去寻找下一个不为空的桶的第一个节点

此时我们需要先计算出当前节点在数组中的位置,然后通过循环判断其后边的位置是否存在桶如果存在,就返回新桶的第一个节点,不存在,就说明所有的桶都走完了,此时返回空指针nullptr


三.完整代码

1.unordered_map

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

2.unordered_set

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

四.总结

关于unordered_map和set就分享这么多,通过前边的知识的分享和掌握,unordered_map和set的实现也是如鱼得水。

喜欢本篇文章的小伙伴记得一键三连,我们下期再见!

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号