C++_线性探测的哈希表

哈希冲突

不同关键字通过相同哈希函数计算出相同的哈希地址,该种现象称为哈希冲突或哈希碰撞。

哈希函数

引起哈希冲突的一个原因可能是:哈希函数设计不够合理。
哈希函数设计原则:哈希函数的定义域必须包括需要存储的全部关键码,而如果散列表允许有m个地址时,其值域必须在0到m-1之间。

线性探测

从发生冲突的位置开始,依次向后探测,直到寻找到下一个空位置为止。

  • 插入
    通过哈希函数获取待插入元素在哈希表中的位置,如果该位置中没有元素则直接插入新元素,如果该位置中有元素发生哈希冲突,使用线性探测找到下一个空位置,插入新元素。

  • 删除
    采用闭散列处理哈希冲突时,不能随便物理删除哈希表中已有的元素,若直接删除元素会影响其他
    元素的搜索。因此线性探测采用标记的伪删除法来删除一个元素。

  • 线性探测优点:实现非常简单

  • 线性探测缺点:一旦发生哈希冲突,所有的冲突连在一起,容易产生数据“堆积”,即:不同关键码占据了可利用的空位置,使得寻找某关键码的位置需要许多次比较,导致搜索效率降低。

代码实现

  • 节点定义
enum State{EMPTY,EXIST,DELETE};

template <class K,class V>
struct HashNode
{
 pair<K, V> _data;
 State _state = EMPTY;
};
  • 结构
template <class K, class V>
class HashTable
{
public:
 typedef HashNode<K, V> Node;
 typedef Node* pNode;
 HashTable(const int n = 10)
 {
  _hs.resize(n);
  _size = 0;
 }
 bool Insert(const pair<K,V>&data);
 void CheckCapacity();
 pNode find(const K& key);
 bool Erase(const K& key);
private:
 vector<Node> _hs;
 size_t _size;
};
  • 插入
template<class K, class V>
bool HashTable<K, V>::Insert(const pair<K, V>& data)
{
 CheckCapacity();
 int id = data.first % _hs.size();//计算索引
 while (_hs[id]._state == EXIST)//当前位置有元素
 {
  if (_hs[id]._data.first == data.first)//判读当前位置的元素的key是否和插入的数据相同
   return false;
  ++id;       //key不同,继续向后遍历,找一个空的位置
  if (id == _hs.size())
   id = 0;
 }
 _hs[id]._data = data;//元素插入
 _hs[id]._state = EXIST;
 ++_size;
 return true;
}
  • 扩容
template<class K, class V>
void HashTable<K, V>::CheckCapacity()
{
 if (_hs.size() == 0 || _size * 10 / _hs.size() >= 8)
 {
  int capacity = _hs.size() == 0 ? 10 : 2 * _hs.size();
  HashTable<K, V> newhs(capacity);
  for (size_t i = 0; i < _hs.size(); ++i)
  {
   if (_hs[i]._state == EXIST)
    newhs.Insert(_hs[i]._data);
  }
  swap(_hs, newhs._hs);
 }
}
  • 搜索
template<class K, class V>
typename HashTable<K, V>:: pNode HashTable<K, V>::find(const K& key)
{
 int id = key % _hs.size();
 while (_hs[id]._state != EMPTY)
 {
  if (_hs[id]._state == EXIST)
  {
   if (_hs[id]._data.first == key)
    return &_hs[id];
  }
  ++id;
  if (id == _hs.size())
   id = 0;
 }
 return nullptr;
}
  • 删除
template<class K, class V>
bool HashTable<K, V>::Erase(const K& key)
{
 pNode pos = find(key);
 if (pos)
 {
  pos->_state = DELETE;
  --_size;
  return true;
 }
 return false;
}
发布了71 篇原创文章 · 获赞 131 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_43239560/article/details/100079816