unordermap 和 unorderset 实现了无序元素的存放,其底层的数据结构是哈希表
哈希表中要让不同类型的数据都能使用除留余数法,
所以在设计哈希表的时候必须要有一个类模板参数可以传入让数据变成整型的函数模板
通过C++的特化,能够让unordermap在插入string 为key值的数据时,
直接走下面的函数,不用再调用的时候专门传入一个仿函数参数
cpp
template<>
struct hashFunc<string>
{
// 由一个字符串生成一个整型数据,需要经过特殊算法的设计,以实现
// 不同的字符串尽可能对应不同的整型数据
size_t operator()(const string& key)
{
size_t hash = 0;
for (auto ch : key)
{
//至于为什么乘上131,请看BKDR算法的具体推导
hash *= 131;
hash += ch;
}
return hash;
}
};
cpp
// 需要注意:__HTIterator的类域中定义_pht的时候,使用了hashTable这个类
// hashTable中返回迭代器的时候,使用了__HTIterator 这个类
// 针对这个问题有两种解决方式,
// 方式一:不使用内部类的架构,就需要进行两个操作:
// 1. 使用以下的前置声明,hashTable这个类以及其对应的模板参数提前,将可以保证编译器不会报错
// 2. 由于__HTIterator中利用了除留余数法,除留余数法需要使用hashTable的私有成员_tables
// 那么可以在hashTable中声明一个友元,将__HTIterator声明为hashTable的友元
//
template<class K, class T, class KeyofT, class Hash>
class hashTable;
template<class K, class Ptr, class Ref, class KeyofT, class Hash>
struct __HTIterator
{
typedef hashNode<T> Node;
typedef __HTIterator<K, T, KeyofT, Hash> Self;
Node* _node;
const hashTable* _pht;
// // 这么设计迭代器是因为要实现 迭代器的 加加++,
// // 只能将哈希桶中的指针数组作为参数传过来
__HTIterator(Node* node, const hashTable* pht)
:_node(node)
,_pht(pht)
{}
Ref operator*()
{
return _node->_data;
}
Ptr operator->()
{
return &(_node->_data);
}
Self& operator++()
{
if (_node->_next)
{
//当前桶没走完,取当前桶的下一个节点
_node = _node->_next;
}
else
{
//当前桶走完,取当前桶的下一个节点
KeyofT kot;
Hash hs;
size_t i = hs(kot(_node->_data)) % _pht->_tables.size();
++i;
for (; i < _pht->_tables.size(); i++)
{
if (_pht->_tables[i])
{
break;
}
}
//针对如果当前vector容器走完的情况,令_node 赋值为nullptr
if (i == _pht->_tables.size())
{
_node = nullptr;
}
else
{
_node = _pht->_tables[i];
}
}
return *this;
}
bool operator!=(const Self& s)
{
return _node != s._node;
}
};