当前位置:   article > 正文

【C++哈希桶(开散列)】_开散列 -- 哈希桶

开散列 -- 哈希桶

1. 开散列(哈希桶)概念

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

  • 散列函数计算:地址=关键码/哈希表的容量

开散列比闭散列的优势

  • 闭散列的思想:找"下一个"为空的位置,那么就会相互冲突,如果冲突的多了,效率就低;
  • 开散列的思想:哈希表的挂单链表,就不会相互冲突

框架:

  1. template<class K>
  2. struct Hash
  3. {
  4. };
  5. // 字符串特化
  6. template<>
  7. struct Hash<string>
  8. {
  9. };
  10. //节点
  11. template<class T, class V>
  12. struct HashNode
  13. {
  14. pair<T, V> _kv;
  15. HashNode<T, V>* _next;
  16. };
  17. //哈希表
  18. template<class T, class V>
  19. class HashTable
  20. {
  21. typedef HashNode<T, V> Node;
  22. public:
  23. bool Erase(const K& key)
  24. Node* Find(const K& key)
  25. bool Insert(const pair<K, V>& kv)
  26. private:
  27. vector<Node*> _tables;
  28. size_t _n = 0;
  29. };

 2.把各种类型转化为整形以及字符串的特化

  1. template<class K>
  2. struct Hash
  3. {
  4. size_t operator()(const K& key)
  5. {
  6. return key;
  7. }
  8. };
  9. // 特化
  10. template<>
  11. struct Hash<string>
  12. {
  13. size_t operator()(const string& s)
  14. {
  15. size_t value = 0;
  16. for (auto e : s)
  17. {
  18. // BKDR,减少哈希冲突
  19. //防止一个桶挂的太长
  20. value *= 31;
  21. value += e;
  22. }
  23. return value;
  24. }
  25. };

3.查询接口函数

  1. Node* Find(const K& key)
  2. {
  3. //数组为空返回空
  4. if (_tables.empty())
  5. {
  6. return nullptr;
  7. }
  8. //仿函数:把key转化为整形
  9. HashFunc hf;
  10. size_t index = hf(key) % _tables.size();
  11. //找在第几个桶
  12. Node* cur = _tables[index];
  13. while (cur)
  14. {
  15. if (cur->_kv.first == key)
  16. {
  17. return cur;
  18. }
  19. else
  20. {
  21. cur = cur->_next;
  22. }
  23. }
  24. return nullptr;
  25. }

4.插入接口函数

  1. bool Insert(const pair<K, V>& kv)
  2. {
  3. //已经之歌元素有插入失败
  4. Node* ret = Find(kv.first);
  5. if (ret)
  6. return false;
  7. HashFunc hf;
  8. // 负载因子 == 1时扩容
  9. if (_n == _tables.size())
  10. {
  11. size_t newSize = _tables.size() == 0 ? 10 : _tables.size() * 2;
  12. vector<Node*> newTables;
  13. newTables.resize(newSize);
  14. for (size_t i = 0; i < _tables.size(); ++i)
  15. {
  16. //每个桶的头,如果为空就下一个桶
  17. Node* cur = _tables[i];
  18. while (cur)
  19. {
  20. //保存一下下一个元素以免找不到
  21. Node* next = cur->_next;
  22. size_t index = hf(cur->_kv.first) % newTables.size();
  23. // 头插,插入顺序不影响
  24. cur->_next = newTables[index];
  25. newTables[index] = cur;
  26. cur = next;
  27. }
  28. _tables[i] = nullptr;
  29. }
  30. _tables.swap(newTables);
  31. }
  32. size_t index = hf(kv.first) % _tables.size();
  33. Node* newnode = new Node(kv);
  34. // 头插
  35. newnode->_next = _tables[index];
  36. _tables[index] = newnode;
  37. ++_n;
  38. return true;
  39. }

5.删除接口函数

  1. bool Erase(const K& key)
  2. {
  3. //数组为空没有删除的元素
  4. if (_tables.empty())
  5. {
  6. return false;
  7. }
  8. HashFunc hf;
  9. size_t index = hf(key) % _tables.size();
  10. //单链表删除保存前一个和后一个
  11. Node* prev = nullptr;
  12. Node* cur = _tables[index];
  13. while (cur)
  14. {
  15. if (cur->_kv.first == key)
  16. {
  17. if (prev == nullptr) // 头删
  18. {
  19. _tables[index] = cur->_next;
  20. }
  21. else // 中间删除
  22. {
  23. prev->_next = cur->_next;
  24. }
  25. --_n;
  26. delete cur;
  27. return true;
  28. }
  29. else
  30. {
  31. prev = cur;
  32. cur = cur->_next;
  33. }
  34. }
  35. return false;
  36. }

 

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

闽ICP备14008679号