一,哈希表的介绍
哈希表是一种通过哈希思想实现的一种数据结构。哈希表这种数据结构的特点便是可以通过一个值快速的定位这个值所在的位置实现插入,删除,查找。在这篇博客里面,我们便来实现一个通过除留余数法实现的一个哈希表。
二,哈希表的实现
1,哈希表的结构
因为这里要实现的是一个除留余数法实现的一个哈希表,所以是要用到线性探测的方法的。所以在哈希表内部的成员里便要一个连续的存储结构,所以便可以用一个vector<>。
vector里面的元素该用什么类型呢?因为要实现一个比较漂亮的哈希表,所以这个哈希表里面的元素最好能够表示当前的状态,所以这里我们得自己定义hashData。还有为了方便的统计哈希表里面的元素个数,我们又得定义一个_n表示哈希表里面的元素个数。
结构定义如下:
enum State
{
EMPTY,//代表空状态
EXIST,//代表存在状态
DELETE//代表删除状态
};
template<class K,class V>
struct hashData
{
State _st;//状态
pair<K, V>_kv;//元素数据
};
template<class K,class V>
class HashTable
{
private:
vector<hashData<K, V>> _hashtables;
size_t _n = 0;//表示元素个数,并且要初始化,并且一定得是size_t类型的变量(预防插入一个关键值为负数的元素)
};
二,插入操作实现
插入操作的实现的实现主要分为以下几步:
1,计算插入值对应的位置。
2,如果这个位置上面已经有元素了便要往后线性探测。(这里便是出现了哈希冲突)
3,如果插入的元素已经把表给填满了便要开新表,然后将旧表中的值重新映射填入到新表中。然后再交换给旧表。
插入操作优化的点:
在插入时最讨厌的便是出现哈希冲突,所以为了减少哈希冲突的出现便可以在定义一个叫做负载因子。一般负载因子的值达到了0.7便要开始扩容。
代码实现如下:
bool Insert(const pair<K, V>key)
{
if (_n * 10 / _hashtables.size() == 7)
{
int newsize = 2 * _hashtables.size();
HashTable<K,V>newHash;
for (int i = 0;i < _hashtables.size();i++)
{
if (_hashtables[i]._st == EXIST)
{
newHash.Insert(_hashtables[i]._kv);
}
}
_hashtables.swap(newHash._hashtables);
}
int hashi = key.first % _hashtables.size();
while (_hashtables[hashi]._st == EXIST)
{
hashi++;
hashi %= _hashtables.size();
}
_hashtables[hashi]._kv = key;
_hashtables[hashi]._st = EXIST;
_n++;
return true;
}
三,查找操作
哈希表的查找操作步骤如下:
1,通过除留余数法计算出hashi。
2,通过hashi定位到指定位置,如果这个指定位置的状态是EMPTY便停止。反之便继续找。
3,找到了便将该位置返回。
4,找不到便返回一个nullptr。
实现代码如下:
hashData<K, V>* Find(const pair<K, V>key)
{
size_t hashi = key .first% _hashtables.size();
while (_hashtables[hashi]._st != EMPTY)
{
if (_hashtables[hashi]._st == EXIST&&_hashtables[hashi]._kv == key)
{
return &_hashtables[hashi];
}
hashi++;
hashi %= _hashtables.size();
}
return nullptr;
}
在实现了查找操作以后便可以在插入操作里面实现一个不能插入相同元素的功能。代码如下:
if (Find(key))
{
return false;
}
四,删除操作
这里的删除操作实现的是一种伪删除法。删除时通过Find()找到对应的值,然后将这个值对应的状态改为DELETE即可。
代码:
bool Erase(const pair<K, V>key)
{
hashData<K, V>* ret = Find(key);
if (ret)
{
ret->_st = DELETE;
return true;
}
return false;
}
五,全部代码
#include<iostream>
#include<vector>
using namespace std;
namespace Hash
{
enum State
{
EMPTY,//代表空状态
EXIST,//代表存在状态
DELETE//代表删除状态
};
template<class K,class V>
struct hashData
{
State _st;//状态
pair<K, V>_kv;//元素数据
};
template<class K,class V>
class HashTable
{
public:
HashTable()
{
_hashtables.resize(10);
}
bool Insert(const pair<K, V>key)
{
if (Find(key))
{
return false;
}
if (_n * 10 / _hashtables.size() == 7)
{
int newsize = 2 * _hashtables.size();
HashTable<K,V>newHash;
for (int i = 0;i < _hashtables.size();i++)
{
if (_hashtables[i]._st == EXIST)
{
newHash.Insert(_hashtables[i]._kv);
}
}
_hashtables.swap(newHash._hashtables);
}
int hashi = key.first % _hashtables.size();
while (_hashtables[hashi]._st == EXIST)
{
hashi++;
hashi %= _hashtables.size();
}
_hashtables[hashi]._kv = key;
_hashtables[hashi]._st = EXIST;
_n++;
return true;
}
hashData<K, V>* Find(const pair<K, V>key)
{
size_t hashi = key .first% _hashtables.size();
while (_hashtables[hashi]._st != EMPTY)
{
if (_hashtables[hashi]._st == EXIST&&_hashtables[hashi]._kv == key)
{
return &_hashtables[hashi];
}
hashi++;
hashi %= _hashtables.size();
}
return nullptr;
}
bool Erase(const pair<K, V>key)
{
hashData<K, V>* ret = Find(key);
if (ret)
{
ret->_st = DELETE;
return true;
}
return false;
}
void Print()
{
for (int i = 0;i < _hashtables.size();i++)
{
if (_hashtables[i]._st == EXIST)
{
printf("->%d\n",_hashtables[i]._kv.second);
}
else if (_hashtables[i]._st == DELETE)
{
printf("%d->D\n", _hashtables[i]._kv.second);
}
else
{
printf("-> \n");
}
}
}
private:
vector<hashData<K, V>> _hashtables;
size_t _n = 0;//表示元素个数,并且要初始化
};
void HT1()
{
HashTable<int, int>hash;
hash.Insert(make_pair<int, int>(1, 1));
hash.Insert(make_pair<int, int>(1, 8));
hash.Insert(make_pair<int, int>(1, 9));
hash.Insert(make_pair<int, int>(1, 12));
hash.Insert(make_pair<int, int>(1, 12));
hash.Insert(make_pair<int, int>(1, 19));
hash.Insert(make_pair<int, int>(1, 10));
hash.Insert(make_pair<int, int>(1, 20));
hash.Erase(make_pair<int, int>(1, 10));
hash.Insert(make_pair<int, int>(1, 30));
hash.Print();
}
}