开门见山,映射表即存放键值对的一种结构。如果我们要在映射表里面存储一个数字3,这个3可以当作是一个键值,如果我们发现在映射表里面3已经存在,那么我们就把它的值加1。如果没有那么它的值为0,然后根据规则插入到映射表。在C++中的map中,键值对是按照pair的形式进行存储的。
接下来我们用链地址法的hash表的来实现这一结构,不了解链地址的hash表的实现可以参考我的另一篇博客链地址法实现hash表。
1.映射表的结构
//储存结点类型
class Node
{
public:
Node(KeyType key = KeyType()) :_key(key), _value(ValueType()) {}
bool operator==(const Node& node)const
{
return _key == node._key;
}
KeyType _key;
ValueType _value;
};
int _nodeSize;//存储结点的个数
int _chainSize;//存储链的个数
vector<list<Node>>_hashMap;//映射表
double _loadFactor;//负载均衡因子
HashType _hashValue;//用于计算哈希值
上面是映射表的成员变量,用Node结构来模拟键值对,用链地址法的hash表_hashMap来模拟映射表的。
2.映射表的插入操作
在进行键的插入操作的时候,先要判断键是否存在,如果存在,把相应的值加1完成操作。不存在,要先根据负载均衡因子来判断映射表是否要进行扩容,如果需要扩容,扩容之后由于_chainSize的改变,要将以前已经存储的元素重新进行存储。然后再将当前键存入到映射表中。
void Insert(KeyType key)
{
//先判断结点是否存在
int index = _hashValue(key) % _chainSize;
for (Node &ele : _hashMap[index])
{
//存在,_value+1,
if (ele._key == key)
{
ele._value++;
cout << "插入成功 value+1" << endl;
++_nodeSize;
return;
}
}
//不存在,根据情况对对映射表进行扩容
int len = GetLen();
if (_hashMap[index].empty())
++len;
//对映射表进行扩容
if ((double)len / _chainSize >= _loadFactor)
{
vector<Node> nodeArr;
//记录以前的元素,需要进行重新存储
for (list<Node> l : _hashMap)
{
for (Node node : l)
{
nodeArr.push_back(node);
}
//链表清空
l.clear();
}
//映射表扩容
_hashMap.resize(2 * _chainSize);
_loadFactor /= 2.0;
_chainSize *= 2;
//重存以前的元素
for (Node node : nodeArr)
{
int location = _hashValue(node._key) % _chainSize;
_hashMap[location].push_back(node);
}
}
index = _hashValue(key)%_chainSize;
_hashMap[index].push_back(Node(key));
++_nodeSize;
cout << "插入成功" << endl;
}
3.删除操作
删除操作,需要先判断键对应的值是否为1,为1的话移除此键,不为1将值减1完成操作。
//删除操作
void Remove(KeyType key)
{
int index = _hashValue(key) % _chainSize;
for (Node &node : _hashMap[index])
{
if (node._key == key)
{
if (node._value !=ValueType())
{
node._value--;
}
else
_hashMap[index].remove(node);
}
}
cout << "删除成功" << endl;
}
4.源码
# include<iostream>
using namespace std;
# include<vector>
# include<list>
//函数对象,映射函数默认用除留余数法,在这里只返回key值
template<typename KeyType>
class CHash
{
public:
KeyType operator() (const KeyType& key )
{
return key;
}
};
template<typename KeyType,typename ValueType,typename HashType = CHash<KeyType>>
class HashMap
{
public:
HashMap(int chainSize=3, double loadFactor = 0.75)
:_nodeSize(0), _chainSize(chainSize), _loadFactor(loadFactor)
{
_hashMap.resize(_chainSize);
}
void Insert(KeyType key)
{
//先判断结点是否存在
int index = _hashValue(key) % _chainSize;
for (Node &ele : _hashMap[index])
{
//存在,_value+1,
if (ele._key == key)
{
ele._value++;
cout << "插入成功 value+1" << endl;
++_nodeSize;
return;
}
}
//不存在,根据情况对对映射表进行扩容
int len = GetLen();
if (_hashMap[index].empty())
++len;
//对映射表进行扩容
if ((double)len / _chainSize >= _loadFactor)
{
vector<Node> nodeArr;
//记录以前的元素,需要进行重新存储
for (list<Node> l : _hashMap)
{
for (Node node : l)
{
nodeArr.push_back(node);
}
//链表清空
l.clear();
}
//映射表扩容
_hashMap.resize(2 * _chainSize);
_loadFactor /= 2.0;
_chainSize *= 2;
//重存以前的元素
for (Node node : nodeArr)
{
int location = _hashValue(node._key) % _chainSize;
_hashMap[location].push_back(node);
}
}
index = _hashValue(key)%_chainSize;
_hashMap[index].push_back(Node(key));
++_nodeSize;
cout << "插入成功" << endl;
}
//得到桶大小
int GetBucketSize()
{
return _chainSize;
}
//得到元素个数
int GetNodeSIze()
{
return _nodeSize;
}
//删除操作
void Remove(KeyType key)
{
int index = _hashValue(key) % _chainSize;
for (Node &node : _hashMap[index])
{
if (node._key == key)
{
if (node._value !=ValueType())
{
node._value--;
}
else
_hashMap[index].remove(node);
}
}
cout << "删除成功" << endl;
}
//查询操作
void Query(const ValueType& key)
{
int index = _hashValue(key) % _chainSize;
for (Node node : _hashMap[index])
{
if (node._key == key)
{
cout << "查询成功" << node._key << ":" << node._value+1 << endl;
return;
}
}
cout << "查无此元素" << endl;
}
private:
int GetLen()
{
int len = 0;
for (list<Node> l: _hashMap)
{
if (!l.empty())
{
++len;
}
}
return len;;
}
private:
//储存结点类型
class Node
{
public:
Node(KeyType key = KeyType()) :_key(key), _value(ValueType()) {}
bool operator==(const Node& node)const
{
return _key == node._key;
}
KeyType _key;
ValueType _value;
};
int _nodeSize;//存储结点的个数
int _chainSize;//存储链的个数
vector<list<Node>>_hashMap;//映射表
double _loadFactor;//负载均衡因子
HashType _hashValue;//用于计算哈希值
};
int main()
{
HashMap<int, int> map(3);
//测试_loadFactor
cout << map.GetBucketSize() << endl;
map.Insert(1);
map.Insert(2);
map.Insert(3);
cout << map.GetBucketSize() << endl;
//测试插入
map.Insert(3);
map.Query(3);
//删除操作
map.Remove(3);
map.Query(3);
return 0;
}
测试结果如下: