当前位置:   article > 正文

【C++进阶】哈希实现unordered_set && unordered_map_c++ 哈希set

c++ 哈希set

1、unordered_map介绍

1. unordered_map是存储<key, value>键值对的关联式容器,其允许通过keys快速的索引到与其对应的value。
2. 在unordered_map中,键值通常用于惟一地标识元素,而映射值是一个对象,其内容与此
键关联。键和映射值的类型可能不同。
3. 在内部,unordered_map没有对<kye, value>按照任何特定的顺序排序, 为了能在常数范围内找到key所对应的value,unordered_map将相同哈希值的键值对放在相同的桶中。
4. unordered_map容器通过key访问单个元素要比map快,但它通常在遍历元素子集的范围迭代方面效率较低。
5. unordered_maps实现了直接访问操作符(operator[]),它允许使用key作为参数直接访问
value。
6. 它的迭代器至少是前向迭代器。
 

 1.1 unordered_map的构造

函数声明功能介绍
unordered_map构造不同格式的unordered_map对象

1.2 unordered_map的容量

函数声明功能介绍
bool empty() const检测unordered_map是否为空
size_t size() const获取unordered_map的有效元素个数

1.3 unordered_map的迭代器

函数声明功能介绍
begin返回unordered_map第一个元素的迭代器
end返回unordered_map最后一个元素下一个位置的迭代器
cbegin返回unordered_map第一个元素的const迭代器
cend返回unordered_map最后一个元素下一个位置的const迭代器

1.4 unordered_map的元素访问

函数声明功能介绍
operator[]返回与key对应的value,没有一个默认值

注意:该函数中实际调用哈希桶的插入操作,用参数key与V()构造一个默认值往底层哈希桶
中插入,如果key不在哈希桶中,插入成功,返回V(),插入失败,说明key已经在哈希桶中,
将key对应的value返回。
 

1.5 unordered_map的查询

函数声明功能介绍
iterator find(const K& key)返回key在哈希桶中的位置
size_t count(const K& key)返回哈希桶中关键码为key的键值对的个数

注意:unordered_map中key是不能重复的,因此count函数的返回值最大为1
 

1.6 unordered_map的修改操作

函数声明功能介绍
insert向容器中插入键值对
erase删除容器中的键值对
void clear()清空容器中有效元素个数
void swap(unordered_map&)交换两个容器中的元素

1.7 unordered_map的桶操作

函数声明功能介绍
size_t bucket_count()const返回哈希桶中桶的总个数
size_t bucket_size(size_t n)const返回n号桶中有效元素的总个数
size_t bucket(const K& key)返回元素key所在的桶号

2、unordered_set介绍

set跟map及其相似,参照map使用即可。

3、相关OJ题

在长度为2N的数组中找出重复N次的元素

  1. class Solution {
  2. public:
  3. int repeatedNTimes(vector<int>& nums) {
  4. int n = nums.size() / 2;
  5. //用unordered_map统计每个元素出现的次数
  6. unordered_map<int, int> m;
  7. for(auto e : nums)
  8. {
  9. m[e]++;
  10. }
  11. //找出出现次数为n的元素
  12. for(auto& e : m)
  13. {
  14. if(e.second == n)
  15. return e.first;
  16. }
  17. return -1;
  18. }
  19. };

 两个数组的交集

  1. class Solution {
  2. public:
  3. vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
  4. //对nums1用unordered_set去重
  5. unordered_set<int> s1;
  6. for(auto e : nums1)
  7. s1.insert(e);
  8. //对nums2用unordered_set去重
  9. unordered_set<int> s2;
  10. for(auto e : nums2)
  11. s2.insert(e);
  12. //遍历s1找出与s2中相同的元素
  13. vector<int> v;
  14. for(auto e : s1)
  15. {
  16. if(s2.find(e) != s2.end())
  17. v.push_back(e);
  18. }
  19. return v;
  20. }
  21. };

4、底层结构

4.1 哈希概念

顺序结构以及平衡树中,元素关键码与其存储位置之间没有对应的关系,因此在查找一个元素时,必须要经过关键码的多次比较。顺序查找时间复杂度为O(N),平衡树中为树的高度,即O(logN),搜索的效率取决于搜索过程中元素的比较次数。
理想的搜索方法:可以不经过任何比较,一次直接从表中得到要搜索的元素。
如果构造一种存储结构,通过某种函数(hashFunc)使元素的存储位置与它的关键码之间能够建立一一映射的关系,那么在查找时通过该函数可以很快找到该元素
 

当向该结构: 

插入元素

根据待插入元素的关键码,以此函数计算出该元素的存储位置并按此位置进行存放。

 搜索元素

对元素的关键码进行同样的计算,把求得的函数值当做元素的存储位置,在结构中按此位置
取元素比较,若关键码相等,则搜索成功。

该方式即为哈希(散列)方法,哈希方法中使用的转换函数称为哈希(散列)函数,构造出来的结构称
为哈希表(Hash Table)(或者称散列表)
 

4.2 哈希冲突

不同关键字通过相同哈希函数计算出相同的哈希地址,该种现象称为哈希冲突哈希碰撞
把具有不同关键码而具有相同哈希地址的数据元素称为“同义词”
 

4.3 哈希函数

引起哈希冲突的一个原因可能是:哈希函数设计不够合理。
哈希函数设计原则

1.哈希函数的定义域必须包括需要存储的全部关键码,而如果散列表允许有m个地址时,其值域必须在0到m-1之间
2.哈希函数计算出来的地址能均匀分布在整个空间中
3.哈希函数应该比较简单

 常见哈希函数:

1.直接定址法(常用)

2.除留余数法(常用)

3.平方取中法

4.折叠法

5.随机数法

6.数学分析法

4.4 哈希冲突如何解决?

4.4.1 闭散列

闭散列是用的线性探测的方法实现,线性探测

线性探测优点:实现非常简单,
线性探测缺点:一旦发生哈希冲突,所有的冲突连在一起,容易产生数据“堆积”,即:不同
关键码占据了可利用的空位置,使得寻找某关键码的位置需要许多次比较,导致搜索效率降
低。
如何更好的缓解这种情况?

可以进行二次探测

  1. #include<vector>
  2. template<class K>
  3. struct HashFunc
  4. {
  5. size_t operator()(const K& key)
  6. {
  7. return (size_t)key;
  8. }
  9. };
  10. //特化
  11. template<>
  12. struct HashFunc<string>
  13. {
  14. size_t operator()(const string& key)
  15. {
  16. size_t hash = 0;
  17. for (auto ch : key)
  18. {
  19. hash *= 131;
  20. hash += ch;
  21. }
  22. return hash;
  23. }
  24. };
  25. //开放地址寻址
  26. namespace open_adress
  27. {
  28. enum State
  29. {
  30. EMPTY,
  31. EXIST,
  32. DELETE
  33. };
  34. template<class K, class V>
  35. struct HashData
  36. {
  37. pair<K, V> _kv;
  38. State _state = EMPTY;
  39. };
  40. template<class K, class V, class Hash = HashFunc<K>>
  41. class HashTable
  42. {
  43. public:
  44. HashTable()
  45. {
  46. _tables.resize(10);
  47. }
  48. bool Insert(const pair<K, V>& kv)
  49. {
  50. if (_n * 10 / _tables.size() >= 7)
  51. {
  52. //扩容
  53. HashTable<K, V, Hash> newHT;
  54. newHT._tables.resize(_tables.size() * 2);
  55. for (size_t i = 0; i < _tables.size(); i++)
  56. {
  57. if (_tables[i]._state == EXIST)
  58. {
  59. newHT.Insert(_tables[i]._kv);
  60. }
  61. }
  62. _tables.swap(newHT._tables);
  63. }
  64. Hash hs;
  65. size_t hashi = hs(kv.first) % _tables.size();
  66. //线性探测
  67. while (_tables[hashi]._state == EXIST)
  68. {
  69. ++hashi;
  70. hashi %= _tables.size();
  71. }
  72. _tables[hashi]._kv = kv;
  73. _tables[hashi]._state = EXIST;
  74. _n++;
  75. return true;
  76. }
  77. HashData<K, V>* Find(const K& key)
  78. {
  79. Hash hs;
  80. size_t hashi = hs(key) % _tables.size();
  81. while (_tables[hashi]._state != EMPTY)
  82. {
  83. if (_tables[hashi]._state == EXIST &&
  84. _tables[hashi]._kv.first == key)
  85. {
  86. return &_tables[hashi];
  87. }
  88. ++hashi;
  89. hashi %= _tables.size();
  90. }
  91. return nullptr;
  92. }
  93. bool Erase(const K& key)
  94. {
  95. HashData<K, V>* ret = Find(key);
  96. if (ret != nullptr)
  97. {
  98. ret->_state = EMPTY;
  99. _n--;
  100. return true;
  101. }
  102. else
  103. {
  104. return false;
  105. }
  106. }
  107. private:
  108. vector<HashData<K, V>> _tables;
  109. size_t _n = 0; //有效数据个数
  110. };
  111. void testHT1()
  112. {
  113. int a[] = { 12, 33434, 223 ,3 };
  114. HashTable<int, int> ht;
  115. for (auto e : a)
  116. {
  117. ht.Insert(make_pair(e, e));
  118. }
  119. cout << ht.Find(12) << endl;
  120. cout << ht.Find(223) << endl;
  121. ht.Erase(223);
  122. cout << ht.Find(12) << endl;
  123. cout << ht.Find(223) << endl;
  124. }
  125. void testHT2()
  126. {
  127. HashTable<string, int> ht;
  128. ht.Insert(make_pair("sort", 1));
  129. ht.Insert(make_pair("left", 2));
  130. ht.Insert(make_pair("right", 3));
  131. ht.Insert(make_pair("ok", 4));
  132. }
  133. }

闭散列最大的缺陷就是空间利用率比较低,这也是哈希的缺陷。
 

4.4.2 开散列

开散列法又叫链地址法(开链法),首先对关键码集合用散列函数计算散列地址,具有相同地
址的关键码归于同一子集合,每一个子集合称为一个桶,各个桶中的元素通过一个单链表链
接起来,各链表的头结点存储在哈希表中。

  1. //哈希桶法
  2. namespace hash_bucket
  3. {
  4. template<class T>
  5. struct HashNode
  6. {
  7. T _data;
  8. HashNode<T>* next;
  9. HashNode(const T& data)
  10. :_data(data)
  11. ,next(nullptr)
  12. {}
  13. };
  14. 前置声明
  15. //template<class K, class T, class KeyOfT, class Hash>
  16. //class HashTable;
  17. //template<class K, class T, class KeyOfT, class Hash>
  18. //struct __HTIterator
  19. //{
  20. // typedef HashNode<T> Node;
  21. // typedef __HTIterator Self;
  22. // Node* _node;
  23. // HashTable<K, T, KeyOfT, Hash>* _pht;
  24. // __HTIterator(Node* node, HashTable<K, T, KeyOfT, Hash>* pht)
  25. // :_node(node)
  26. // ,_pht(pht)
  27. // {}
  28. // Self& operator++()
  29. // {
  30. // if (_node->next)
  31. // {
  32. // //当前桶没走完,找当前桶的下一个节点
  33. // _node = _node->next;
  34. // }
  35. // else
  36. // {
  37. // //当前桶走完了,找下一个不为空的桶的第一个节点
  38. // KeyOfT kot;
  39. // Hash hs;
  40. // size_t i = hs(kot(_node->_data)) % _pht->_tables.size();
  41. // ++i;
  42. // for (; i < _pht->_tables.size(); i++)
  43. // {
  44. // if (_pht->_tables)
  45. // break;
  46. // }
  47. // if (i == _pht->_tables.size())
  48. // {
  49. // //所有桶都走完了,最后一个的下一个用nullptr标记
  50. // _node = nullptr;
  51. // }
  52. // else
  53. // {
  54. // _node = _pht->_tables[i];
  55. // }
  56. // }
  57. // return *this;
  58. // }
  59. // bool operator!=(const Self& s)
  60. // {
  61. // return _node != s._node;
  62. // }
  63. //};
  64. template<class K, class T, class KeyOfT, class Hash>
  65. class HashTable
  66. {
  67. typedef HashNode<T> Node;
  68. public:
  69. 友元声明
  70. //template<class K, class T, class KeyOfT, class Hash>
  71. //friend class HashTable;
  72. template<class Ptr, class Ref>
  73. struct __HTIterator
  74. {
  75. typedef HashNode<T> Node;
  76. typedef __HTIterator Self;
  77. Node* _node;
  78. HashTable* _pht;
  79. __HTIterator(Node* node, HashTable* pht)
  80. :_node(node)
  81. , _pht(pht)
  82. {}
  83. Ref operator*()
  84. {
  85. return _node->_data;
  86. }
  87. Ptr operator->()
  88. {
  89. return &_node->_data;
  90. }
  91. Self& operator++()
  92. {
  93. if (_node->next)
  94. {
  95. //当前桶没走完,找当前桶的下一个节点
  96. _node = _node->next;
  97. }
  98. else
  99. {
  100. //当前桶走完了,找下一个不为空的桶的第一个节点
  101. KeyOfT kot;
  102. Hash hs;
  103. size_t i = hs(kot(_node->_data)) % _pht->_tables.size();
  104. ++i;
  105. for (; i < _pht->_tables.size(); i++)
  106. {
  107. if (_pht->_tables[i])
  108. break;
  109. }
  110. if (i == _pht->_tables.size())
  111. {
  112. //所有桶都走完了,最后一个的下一个用nullptr标记
  113. _node = nullptr;
  114. }
  115. else
  116. {
  117. _node = _pht->_tables[i];
  118. }
  119. }
  120. return *this;
  121. }
  122. bool operator!=(const Self& s)
  123. {
  124. return _node != s._node;
  125. }
  126. };
  127. typedef __HTIterator<T*, T&> iterator;
  128. typedef __HTIterator<const T*, const T&> const_iterator;
  129. iterator begin()
  130. {
  131. for (size_t i = 0; i < _tables.size(); i++)
  132. {
  133. Node* cur = _tables[i];
  134. if (cur)
  135. {
  136. //this --> HashTable*
  137. return iterator(cur, this);
  138. }
  139. }
  140. return end();
  141. }
  142. iterator end()
  143. {
  144. return iterator(nullptr, this);
  145. }
  146. const_iterator begin() const
  147. {
  148. for (size_t i = 0; i < _tables.size(); i++)
  149. {
  150. Node* cur = _tables[i];
  151. if (cur)
  152. {
  153. //this --> HashTable*
  154. return const_iterator(cur, this);
  155. }
  156. }
  157. return end();
  158. }
  159. const_iterator end() const
  160. {
  161. return const_iterator(nullptr, this);
  162. }
  163. HashTable()
  164. {
  165. _tables.resize(10, nullptr);
  166. _n = 0;
  167. }
  168. ~HashTable()
  169. {
  170. for (size_t i = 0; i < _tables.size(); i++)
  171. {
  172. Node* cur = _tables[i];
  173. while (cur)
  174. {
  175. Node* next = cur->next;
  176. delete cur;
  177. cur = next;
  178. }
  179. _tables[i] = nullptr;
  180. }
  181. }
  182. pair<iterator, bool> Insert(const T& data)
  183. {
  184. Hash hs;
  185. KeyOfT kot;
  186. iterator it = Find(kot(data));
  187. if (it != end())
  188. return make_pair(it, false);
  189. //扩容
  190. //负载因子为1时需要扩容
  191. if (_n == _tables.size())
  192. {
  193. vector<Node*> newTables(_tables.size() * 2, nullptr);
  194. for (size_t i = 0; i < _tables.size(); i++)
  195. {
  196. Node* cur = _tables[i];
  197. while (cur)
  198. {
  199. Node* next = cur->next;
  200. //头插新表的位置
  201. size_t hashi = hs(kot(cur->_data)) % newTables.size();
  202. cur->next = newTables[hashi];
  203. newTables[hashi] = cur;
  204. cur = next;
  205. }
  206. }
  207. _tables.swap(newTables);
  208. }
  209. size_t hashi = hs(kot(data)) % _tables.size();
  210. //头插
  211. Node* newnode = new Node(data);
  212. newnode->next = _tables[hashi];
  213. _tables[hashi] = newnode;
  214. ++_n;
  215. return make_pair(iterator(newnode, this), true);
  216. }
  217. iterator Find(const K& key)
  218. {
  219. Hash hs;
  220. KeyOfT kot;
  221. size_t hashi = hs(key) % _tables.size();
  222. Node* cur = _tables[hashi];
  223. while (cur)
  224. {
  225. if (kot(cur->_data) == key)
  226. {
  227. return iterator(cur, this);
  228. }
  229. cur = cur->next;
  230. }
  231. return end();
  232. }
  233. bool Erase(const K& key)
  234. {
  235. Hash hs;
  236. KeyOfT kot;
  237. size_t hashi = hs(key) % _tables.size();
  238. Node* prev = nullptr;
  239. Node* cur = _tables[hashi];
  240. while (cur)
  241. {
  242. if (kot(cur->_data) == key)
  243. {
  244. //删除的是第一个
  245. if (prev == nullptr)
  246. {
  247. _tables[hashi] = cur->next;
  248. }
  249. else
  250. {
  251. prev->next = cur->next;
  252. }
  253. delete cur;
  254. return true;
  255. }
  256. else
  257. {
  258. prev = cur;
  259. cur = cur->next;
  260. }
  261. }
  262. return false;
  263. }
  264. private:
  265. vector<Node*> _tables;
  266. size_t _n;
  267. };
  268. }

 4.4.3 闭散列与开散列比较

应用链地址法处理溢出,需要增设链接指针,似乎增加了存储开销。事实上:
由于开地址法必须保持大量的空闲空间以确保搜索效率,如二次探查法要求装载因子a <=
0.7,而表项所占空间又比指针大的多,所以使用链地址法反而比开地址法节省存储空间。

5、模拟实现

5.1 unordered_map模拟实现

  1. #pragma once
  2. namespace bit
  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. typedef typename hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT, Hash>::const_iterator const_iterator;
  17. iterator begin()
  18. {
  19. return _ht.begin();
  20. }
  21. iterator end()
  22. {
  23. return _ht.end();
  24. }
  25. const_iterator begin() const
  26. {
  27. return _ht.begin();
  28. }
  29. const_iterator end() const
  30. {
  31. return _ht.end();
  32. }
  33. pair<iterator, bool> insert(const pair<K, V>& kv)
  34. {
  35. return _ht.Insert(kv);
  36. }
  37. bool Erase(const K& key)
  38. {
  39. return _ht.Erase(key);
  40. }
  41. V& operator[](const K& key)
  42. {
  43. pair<iterator, bool> ret = insert(make_pair(key, V()));
  44. return ret.first->second;
  45. }
  46. private:
  47. hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT, Hash> _ht;
  48. };
  49. void test_unordered_map()
  50. {
  51. string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜",
  52. "苹果", "香蕉", "苹果", "香蕉","苹果","草莓", "苹果","草莓" };
  53. unordered_map<string, int> countMap;
  54. for (auto& e : arr)
  55. {
  56. countMap[e]++;
  57. }
  58. unordered_map<string, int>::iterator it = countMap.begin();
  59. while (it != countMap.end())
  60. {
  61. //it->first += 'x'; // key不能修改
  62. it->second += 1; // value可以修改
  63. cout << it->first << ":" << it->second << endl;
  64. ++it;
  65. }
  66. cout << endl;
  67. for (auto& kv : countMap)
  68. {
  69. cout << kv.first << ":" << kv.second << endl;
  70. }
  71. cout << endl;
  72. }
  73. }

5.2 unordered_set模拟实现

  1. #pragma once
  2. namespace bit
  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. typedef typename hash_bucket::HashTable<K, const K, SetKeyOfT, Hash>::const_iterator const_iterator;
  17. iterator begin()
  18. {
  19. return _ht.begin();
  20. }
  21. iterator end()
  22. {
  23. return _ht.end();
  24. }
  25. const_iterator begin() const
  26. {
  27. return _ht.begin();
  28. }
  29. const_iterator end() const
  30. {
  31. return _ht.end();
  32. }
  33. pair<iterator, bool> insert(const K& key)
  34. {
  35. return _ht.Insert(key);
  36. }
  37. bool Erase(const K& key)
  38. {
  39. return _ht.Erase(key);
  40. }
  41. private:
  42. hash_bucket::HashTable<K, const K, SetKeyOfT, Hash> _ht;
  43. };
  44. }

5.3 HashTable模拟实现

  1. #pragma once
  2. #include<vector>
  3. template<class K>
  4. struct HashFunc
  5. {
  6. size_t operator()(const K& key)
  7. {
  8. return (size_t)key;
  9. }
  10. };
  11. //特化
  12. template<>
  13. struct HashFunc<string>
  14. {
  15. size_t operator()(const string& key)
  16. {
  17. size_t hash = 0;
  18. for (auto ch : key)
  19. {
  20. hash *= 131;
  21. hash += ch;
  22. }
  23. return hash;
  24. }
  25. };
  26. //开放地址寻址
  27. namespace open_adress
  28. {
  29. enum State
  30. {
  31. EMPTY,
  32. EXIST,
  33. DELETE
  34. };
  35. template<class K, class V>
  36. struct HashData
  37. {
  38. pair<K, V> _kv;
  39. State _state = EMPTY;
  40. };
  41. template<class K, class V, class Hash = HashFunc<K>>
  42. class HashTable
  43. {
  44. public:
  45. HashTable()
  46. {
  47. _tables.resize(10);
  48. }
  49. bool Insert(const pair<K, V>& kv)
  50. {
  51. if (_n * 10 / _tables.size() >= 7)
  52. {
  53. //扩容
  54. HashTable<K, V, Hash> newHT;
  55. newHT._tables.resize(_tables.size() * 2);
  56. for (size_t i = 0; i < _tables.size(); i++)
  57. {
  58. if (_tables[i]._state == EXIST)
  59. {
  60. newHT.Insert(_tables[i]._kv);
  61. }
  62. }
  63. _tables.swap(newHT._tables);
  64. }
  65. Hash hs;
  66. size_t hashi = hs(kv.first) % _tables.size();
  67. //线性探测
  68. while (_tables[hashi]._state == EXIST)
  69. {
  70. ++hashi;
  71. hashi %= _tables.size();
  72. }
  73. _tables[hashi]._kv = kv;
  74. _tables[hashi]._state = EXIST;
  75. _n++;
  76. return true;
  77. }
  78. HashData<K, V>* Find(const K& key)
  79. {
  80. Hash hs;
  81. size_t hashi = hs(key) % _tables.size();
  82. while (_tables[hashi]._state != EMPTY)
  83. {
  84. if (_tables[hashi]._state == EXIST &&
  85. _tables[hashi]._kv.first == key)
  86. {
  87. return &_tables[hashi];
  88. }
  89. ++hashi;
  90. hashi %= _tables.size();
  91. }
  92. return nullptr;
  93. }
  94. bool Erase(const K& key)
  95. {
  96. HashData<K, V>* ret = Find(key);
  97. if (ret != nullptr)
  98. {
  99. ret->_state = EMPTY;
  100. _n--;
  101. return true;
  102. }
  103. else
  104. {
  105. return false;
  106. }
  107. }
  108. private:
  109. vector<HashData<K, V>> _tables;
  110. size_t _n = 0; //有效数据个数
  111. };
  112. void testHT1()
  113. {
  114. int a[] = { 12, 33434, 223 ,3 };
  115. HashTable<int, int> ht;
  116. for (auto e : a)
  117. {
  118. ht.Insert(make_pair(e, e));
  119. }
  120. cout << ht.Find(12) << endl;
  121. cout << ht.Find(223) << endl;
  122. ht.Erase(223);
  123. cout << ht.Find(12) << endl;
  124. cout << ht.Find(223) << endl;
  125. }
  126. void testHT2()
  127. {
  128. HashTable<string, int> ht;
  129. ht.Insert(make_pair("sort", 1));
  130. ht.Insert(make_pair("left", 2));
  131. ht.Insert(make_pair("right", 3));
  132. ht.Insert(make_pair("ok", 4));
  133. }
  134. }
  135. //哈希桶法
  136. namespace hash_bucket
  137. {
  138. template<class T>
  139. struct HashNode
  140. {
  141. T _data;
  142. HashNode<T>* next;
  143. HashNode(const T& data)
  144. :_data(data)
  145. ,next(nullptr)
  146. {}
  147. };
  148. 前置声明
  149. //template<class K, class T, class KeyOfT, class Hash>
  150. //class HashTable;
  151. //template<class K, class T, class KeyOfT, class Hash>
  152. //struct __HTIterator
  153. //{
  154. // typedef HashNode<T> Node;
  155. // typedef __HTIterator Self;
  156. // Node* _node;
  157. // HashTable<K, T, KeyOfT, Hash>* _pht;
  158. // __HTIterator(Node* node, HashTable<K, T, KeyOfT, Hash>* pht)
  159. // :_node(node)
  160. // ,_pht(pht)
  161. // {}
  162. // Self& operator++()
  163. // {
  164. // if (_node->next)
  165. // {
  166. // //当前桶没走完,找当前桶的下一个节点
  167. // _node = _node->next;
  168. // }
  169. // else
  170. // {
  171. // //当前桶走完了,找下一个不为空的桶的第一个节点
  172. // KeyOfT kot;
  173. // Hash hs;
  174. // size_t i = hs(kot(_node->_data)) % _pht->_tables.size();
  175. // ++i;
  176. // for (; i < _pht->_tables.size(); i++)
  177. // {
  178. // if (_pht->_tables)
  179. // break;
  180. // }
  181. // if (i == _pht->_tables.size())
  182. // {
  183. // //所有桶都走完了,最后一个的下一个用nullptr标记
  184. // _node = nullptr;
  185. // }
  186. // else
  187. // {
  188. // _node = _pht->_tables[i];
  189. // }
  190. // }
  191. // return *this;
  192. // }
  193. // bool operator!=(const Self& s)
  194. // {
  195. // return _node != s._node;
  196. // }
  197. //};
  198. template<class K, class T, class KeyOfT, class Hash>
  199. class HashTable
  200. {
  201. typedef HashNode<T> Node;
  202. public:
  203. 友元声明
  204. //template<class K, class T, class KeyOfT, class Hash>
  205. //friend class HashTable;
  206. template<class Ptr, class Ref>
  207. struct __HTIterator
  208. {
  209. typedef HashNode<T> Node;
  210. typedef __HTIterator Self;
  211. Node* _node;
  212. HashTable* _pht;
  213. __HTIterator(Node* node, HashTable* pht)
  214. :_node(node)
  215. , _pht(pht)
  216. {}
  217. Ref operator*()
  218. {
  219. return _node->_data;
  220. }
  221. Ptr operator->()
  222. {
  223. return &_node->_data;
  224. }
  225. Self& operator++()
  226. {
  227. if (_node->next)
  228. {
  229. //当前桶没走完,找当前桶的下一个节点
  230. _node = _node->next;
  231. }
  232. else
  233. {
  234. //当前桶走完了,找下一个不为空的桶的第一个节点
  235. KeyOfT kot;
  236. Hash hs;
  237. size_t i = hs(kot(_node->_data)) % _pht->_tables.size();
  238. ++i;
  239. for (; i < _pht->_tables.size(); i++)
  240. {
  241. if (_pht->_tables[i])
  242. break;
  243. }
  244. if (i == _pht->_tables.size())
  245. {
  246. //所有桶都走完了,最后一个的下一个用nullptr标记
  247. _node = nullptr;
  248. }
  249. else
  250. {
  251. _node = _pht->_tables[i];
  252. }
  253. }
  254. return *this;
  255. }
  256. bool operator!=(const Self& s)
  257. {
  258. return _node != s._node;
  259. }
  260. };
  261. typedef __HTIterator<T*, T&> iterator;
  262. typedef __HTIterator<const T*, const T&> const_iterator;
  263. iterator begin()
  264. {
  265. for (size_t i = 0; i < _tables.size(); i++)
  266. {
  267. Node* cur = _tables[i];
  268. if (cur)
  269. {
  270. //this --> HashTable*
  271. return iterator(cur, this);
  272. }
  273. }
  274. return end();
  275. }
  276. iterator end()
  277. {
  278. return iterator(nullptr, this);
  279. }
  280. const_iterator begin() const
  281. {
  282. for (size_t i = 0; i < _tables.size(); i++)
  283. {
  284. Node* cur = _tables[i];
  285. if (cur)
  286. {
  287. //this --> HashTable*
  288. return const_iterator(cur, this);
  289. }
  290. }
  291. return end();
  292. }
  293. const_iterator end() const
  294. {
  295. return const_iterator(nullptr, this);
  296. }
  297. HashTable()
  298. {
  299. _tables.resize(10, nullptr);
  300. _n = 0;
  301. }
  302. ~HashTable()
  303. {
  304. for (size_t i = 0; i < _tables.size(); i++)
  305. {
  306. Node* cur = _tables[i];
  307. while (cur)
  308. {
  309. Node* next = cur->next;
  310. delete cur;
  311. cur = next;
  312. }
  313. _tables[i] = nullptr;
  314. }
  315. }
  316. pair<iterator, bool> Insert(const T& data)
  317. {
  318. Hash hs;
  319. KeyOfT kot;
  320. iterator it = Find(kot(data));
  321. if (it != end())
  322. return make_pair(it, false);
  323. //扩容
  324. //负载因子为1时需要扩容
  325. if (_n == _tables.size())
  326. {
  327. vector<Node*> newTables(_tables.size() * 2, nullptr);
  328. for (size_t i = 0; i < _tables.size(); i++)
  329. {
  330. Node* cur = _tables[i];
  331. while (cur)
  332. {
  333. Node* next = cur->next;
  334. //头插新表的位置
  335. size_t hashi = hs(kot(cur->_data)) % newTables.size();
  336. cur->next = newTables[hashi];
  337. newTables[hashi] = cur;
  338. cur = next;
  339. }
  340. }
  341. _tables.swap(newTables);
  342. }
  343. size_t hashi = hs(kot(data)) % _tables.size();
  344. //头插
  345. Node* newnode = new Node(data);
  346. newnode->next = _tables[hashi];
  347. _tables[hashi] = newnode;
  348. ++_n;
  349. return make_pair(iterator(newnode, this), true);
  350. }
  351. iterator Find(const K& key)
  352. {
  353. Hash hs;
  354. KeyOfT kot;
  355. size_t hashi = hs(key) % _tables.size();
  356. Node* cur = _tables[hashi];
  357. while (cur)
  358. {
  359. if (kot(cur->_data) == key)
  360. {
  361. return iterator(cur, this);
  362. }
  363. cur = cur->next;
  364. }
  365. return end();
  366. }
  367. bool Erase(const K& key)
  368. {
  369. Hash hs;
  370. KeyOfT kot;
  371. size_t hashi = hs(key) % _tables.size();
  372. Node* prev = nullptr;
  373. Node* cur = _tables[hashi];
  374. while (cur)
  375. {
  376. if (kot(cur->_data) == key)
  377. {
  378. //删除的是第一个
  379. if (prev == nullptr)
  380. {
  381. _tables[hashi] = cur->next;
  382. }
  383. else
  384. {
  385. prev->next = cur->next;
  386. }
  387. delete cur;
  388. return true;
  389. }
  390. else
  391. {
  392. prev = cur;
  393. cur = cur->next;
  394. }
  395. }
  396. return false;
  397. }
  398. private:
  399. vector<Node*> _tables;
  400. size_t _n;
  401. };
  402. }

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号