目录
- //每个哈希桶中存储数据的结构
- template<class K, class V>
- struct HashNode
- {
- pair
_kv; - HashNode
* _next; -
- //构造函数
- HashNode(const pair
& kv) - :_kv(kv)
- , _next(nullptr)
- {}
- };
-
- //哈希表
- template<class K, class V>
- class HashTable
- {
- typedef HashNode
Node; //哈希结点类型 - public:
-
- //获取本次增容后哈希表的大小
- size_t GetNextPrime(size_t prime)
- {
- const int PRIMECOUNT = 28;
- //素数序列
- const size_t primeList[PRIMECOUNT] =
- {
- 53ul, 97ul, 193ul, 389ul, 769ul,
- 1543ul, 3079ul, 6151ul, 12289ul, 24593ul,
- 49157ul, 98317ul, 196613ul, 393241ul, 786433ul,
- 1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul,
- 50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul,
- 1610612741ul, 3221225473ul, 4294967291ul
- };
-
- size_t i = 0;
- for (i = 0; i < PRIMECOUNT; i++)
- {
- if (primeList[i] > prime)
- return primeList[i];
- }
- return primeList[i];
- }
-
-
- //插入函数
- bool Insert(const pair
& kv) - {
- //1、查看哈希表中是否存在该键值的键值对
- Node* ret = Find(kv.first);
- if (ret) //哈希表中已经存在该键值的键值对(不允许数据冗余)
- {
- return false; //插入失败
- }
-
- //2、判断是否需要调整哈希表的大小
- if (_n == _table.size()) //哈希表的大小为0,或负载因子超过1
- {
- //增容
- //a、创建一个新的哈希表,新哈希表的大小设置为原哈希表的2倍(若哈希表大小为0,则将哈希表的初始大小设置为10)
- vector
newtable; -
- newtable.resize(GetNextPrime(_table.size()));
-
- //b、将原哈希表当中的结点插入到新哈希表
- for (size_t i = 0; i < _table.size(); i++)
- {
- if (_table[i]) //桶不为空
- {
- Node* cur = _table[i];
- while (cur) //将该桶的结点取完为止
- {
- Node* next = cur->_next; //记录cur的下一个结点
- size_t index = cur->_kv.first%newtable.size(); //通过哈希函数计算出对应的哈希桶编号index(除数不能是capacity)
- //将该结点头插到新哈希表中编号为index的哈希桶中
- cur->_next = newtable[index];
- newtable[index] = cur;
-
- cur = next; //取原哈希表中该桶的下一个结点
- }
- _table[i] = nullptr; //该桶取完后将该桶置空
- }
- }
- //c、交换这两个哈希表
- _table.swap(newtable);
- }
-
- //3、将键值对插入哈希表
- size_t index = kv.first % _table.size(); //通过哈希函数计算出对应的哈希桶编号index(除数不能是capacity)
- Node* newnode = new Node(kv); //根据所给数据创建一个待插入结点
- //将该结点头插到新哈希表中编号为index的哈希桶中
- newnode->_next = _table[index];
- _table[index] = newnode;
-
- //4、哈希表中的有效元素个数加一
- _n++;
- return true;
- }
-
- //查找函数
- HashNode
* Find(const K& key) - {
- if (_table.size() == 0) //哈希表大小为0,查找失败
- {
- return nullptr;
- }
-
- size_t index = key % _table.size(); //通过哈希函数计算出对应的哈希桶编号index(除数不能是capacity)
- //遍历编号为index的哈希桶
- HashNode
* cur = _table[index]; - while (cur) //直到将该桶遍历完为止
- {
- if (cur->_kv.first == key) //key值匹配,则查找成功
- {
- return cur;
- }
- cur = cur->_next;
- }
- return nullptr; //直到该桶全部遍历完毕还没有找到目标元素,查找失败
- }
-
- //删除函数
- bool Erase(const K& key)
- {
- //1、通过哈希函数计算出对应的哈希桶编号index(除数不能是capacity)
- size_t index = key % _table.size();
- //2、在编号为index的哈希桶中寻找待删除结点
- Node* prev = nullptr;
- Node* cur = _table[index];
- while (cur) //直到将该桶遍历完为止
- {
- if (cur->_kv.first == key) //key值匹配,则查找成功
- {
- //3、若找到了待删除结点,则删除该结点
- if (prev == nullptr) //待删除结点是哈希桶中的第一个结点
- {
- _table[index] = cur->_next; //将第一个结点从该哈希桶中移除
- }
- else //待删除结点不是哈希桶的第一个结点
- {
- prev->_next = cur->_next; //将该结点从哈希桶中移除
- }
- delete cur; //释放该结点
-
- //4、删除结点后,将哈希表中的有效元素个数减一
- _n--;
- return true; //删除成功
- }
- prev = cur;
- cur = cur->_next;
- }
- //假删除可能会导致迭代器失效
-
- return false; //直到该桶全部遍历完毕还没有找到待删除元素,删除失败
- }
- private:
- vector
_table; //哈希表 - size_t _n = 0; //哈希表中的有效元素个数
- };
(1)用一份哈希表代码同时封装出K模型和KV模型的容器,我们必定要对哈希表的模板参数进行控制。
①与原哈希表的模板参数进行区分,这里将哈希表的第二个模板参数的名字改为T
- template<class K, class T>
- class HashTable
②如果上层使用的是unordered_set容器,那么传入哈希表的模板参数就是key和key
- template<class K>
- class unordered_set
- {
- public:
- //...
- private:
- HashTable
_ht; //传入底层哈希表的是K和K - };
③如果上层使用的是unordered_map容器,那么传入哈希表的模板参数就是key以及key和value构成的键值对
- template<class K, class V>
- class unordered_map
- {
- public:
- //...
- private:
- HashTable
> _ht; //传入底层哈希表的是K以及K和V构成的键值对 - };
④哈希表中的模板参数T的类型到底是什么,完全却决于上层所使用容器的种类。

⑤更改模板参数后,哈希结点的定义如下
- //哈希结点的定义
- template<class T>
- struct HashNode
- {
- T _data;
- HashNode
* _next; -
- //构造函数
- HashNode(const T& data)
- :_data(data)
- , _next(nullptr)
- {}
- };
(2)仿函数获取键值
现在由于我们在哈希结点当中存储的数据类型是T,这个T可能就是一个键值,也可能是一个键值对,对于底层的哈希表来说,它并不知道哈希结点当中存储的数据究竟是什么类型,因此需要由上层容器提供一个仿函数,用于获取T类型数据当中的键值。
①unordered_map容器需要向底层哈希表提供一个仿函数,该仿函数返回键值对当中的键值。
- template<class K, class V>
- class unordered_map
- {
- //仿函数
- struct MapKeyOfT
- {
- const K& operator()(const pair
& kv) //返回键值对当中的键值key - {
- return kv.first;
- }
- };
- public:
- //...
- private:
- HashTable
, MapKeyOfT> _ht; - };
②unordered_set容器传入哈希表的T就是键值,但是底层哈希表并不知道上层容器的种类,底层哈希表在获取键值时会统一通过传入的仿函数进行获取,因此unordered_set容器也需要向底层哈希表提供一个仿函数。
- template<class K>
- class unordered_set
- {
- //仿函数
- struct SetKeyOfT
- {
- const K& operator()(const K& key) //返回键值key
- {
- return key;
- }
- };
- public:
- //...
- private:
- HashTable
_ht; - };
··
③底层哈希表的模板参数现在需要增加一个,用于接收上层容器提供的仿函数。
- template<class K, class T, class KeyOfT>
- class HashTable
(1)字符串无法取模,是哈希问题中最常见的问题
(2)BKDRHash算法无论是在实际效果还是编码实现中,效果都是最突出的
①现在我们需要在哈希表的模板参数中再增加一个仿函数,用于将键值key转换成对应的整型。
- template<class K, class T, class KeyOfT, class HashFunc = Hash
> - class HashTable
②若是上层没有传入该仿函数,我们则使用默认的仿函数,该默认仿函数直接返回键值key即可,但是用字符串作为键值key是比较常见的,因此我们可以针对string类型写一个类模板的特化,此时当键值key为string类型时,该仿函数就会根据BKDRHash算法返回一个对应的整型。
- template<class K>
- struct Hash
- {
- size_t operator()(const K& key) //返回键值key
- {
- return key;
- }
- };
-
- //string类型的特化
- template<>
- struct Hash
- {
- size_t operator()(const string& s) //BKDRHash算法
- {
- size_t value = 0;
- for (auto ch : s)
- {
- value = value * 131 + ch;
- }
- return value;
- }
- };
(1)构造函数
- vector
_table; //哈希表 - size_t _n = 0; //哈希表中的有效元素个数
- //构造函数
- HashTable() = default; //显示指定生成默认构造函数
(2)拷贝构造函数
哈希表的拷贝构造函数(深拷贝)实现逻辑如下:
- //拷贝构造函数
- HashTable(const HashTable& ht)
- {
- //1、将哈希表的大小调整为ht._table的大小
- _table.resize(ht._table.size());
-
- //2、将ht._table每个桶当中的结点一个个拷贝到自己的哈希表中(深拷贝)
- for (size_t i = 0; i < ht._table.size(); i++)
- {
- if (ht._table[i]) //桶不为空
- {
- Node* cur = ht._table[i];
- while (cur) //将该桶的结点取完为止
- {
- Node* copy = new Node(cur->_data); //创建拷贝结点
- //将拷贝结点头插到当前桶
- copy->_next = _table[i];
- _table[i] = copy;
- cur = cur->_next; //取下一个待拷贝结点
- }
- }
- }
-
- //3、更改哈希表当中的有效数据个数
- _n = ht._n;
- }
(3)赋值运算符重载函数
- //赋值运算符重载函数
- HashTable& operator=(HashTable ht)
- {
- //交换哈希表中两个成员变量的数据
- _table.swap(ht._table);
- swap(_n, ht._n);
-
- return *this; //支持连续赋值
- }
(4)析构函数
- //析构函数
- ~HashTable()
- {
- //将哈希表当中的结点一个个释放
- for (size_t i = 0; i < _table.size(); i++)
- {
- if (_table[i]) //桶不为空
- {
- Node* cur = _table[i];
- while (cur) //将该桶的结点取完为止
- {
- Node* next = cur->_next; //记录下一个结点
- delete cur; //释放结点
- cur = next;
- }
- _table[i] = nullptr; //将该哈希桶置空
- }
- }
- }
(1)哈希表的正向迭代器实际上就是对哈希结点指针进行了封装,但是由于在实现++运算符重载时,可能需要在哈希表中去寻找下一个非空哈希桶,因此每一个正向迭代器中都应该存储哈希表的地址。
- //正向迭代器
- template<class K, class T, class KeyOfT, class HashFunc = Hash
> - struct __HTIterator
- {
- typedef HashNode
Node; //哈希结点的类型 - typedef HashTable
HT; //哈希表的类型 - typedef __HTIterator
Self; //正向迭代器的类型 -
- Node* _node; //结点指针
- HT* _pht; //哈希表的地址
- };
(2)其他的实现
- //构造函数
- __HTIterator(Node* node, HT* pht)
- :_node(node) //结点指针
- , _pht(pht) //哈希表地址
- {}
-
- T& operator*()
- {
- return _node->_data; //返回哈希结点中数据的引用
- }
-
- T* operator->()
- {
- return &_node->_data; //返回哈希结点中数据的地址
- }
-
- bool operator!=(const Self& s) const
- {
- return _node != s._node; //判断两个结点的地址是否不同
- }
-
- bool operator==(const Self& s) const
- {
- return _node == s._node; //判断两个结点的地址是否相同
- }
(3)++运算符重载
- //前置++
- Self& operator++()
- {
- if (_node->_next) //该结点不是当前哈希桶中的最后一个结点
- {
- _node = _node->_next; //++后变为当前哈希桶中的下一个结点
- }
- else //该结点是当前哈希桶中的最后一个结点
- {
- KeyOfT kot;
- HashFunc hf;
- size_t index = hf(kot(_node->_data)) % _pht->_table.size(); //通过哈希函数计算出当前所处哈希桶编号index(除数不能是capacity)
-
- index++; //从下一个位置开始找一个非空的哈希桶
- while (index < _pht->_table.size()) //直到将整个哈希表找完
- {
- if (_pht->_table[index]) //当前哈希桶非空
- {
- _node = _pht->_table[index]; //++后变为当前哈希桶中的第一个结点
- return *this;
- }
- index++; //当前哈希桶为空桶,找下一个哈希桶
- }
- _node = nullptr; //哈希表中已经没有空桶了,++后变为nullptr
- }
- return *this;
- }
(4)哈希表的其他实现方式

- //哈希表的实现
- template<class K, class T, class KeyOfT, class HashFunc = Hash
> - class HashTable
- {
- //将正向迭代器类声明为哈希表类的友元
- template<class K, class T, class KeyOfT, class HashFunc>
- friend struct __HTIterator;
-
- typedef HashNode
Node; //哈希结点类型 - public:
- typedef __HTIterator
iterator; //正向迭代器的类型 -
- iterator begin()
- {
- size_t i = 0;
- while (i < _table.size()) //找到第一个非空哈希桶
- {
- if (_table[i]) //该哈希桶非空
- {
- return iterator(_table[i], this); //返回该哈希桶中的第一个结点的正向迭代器
- }
- i++;
- }
- return end(); //哈希桶中无数据,返回end()
- }
-
- iterator end()
- {
- return iterator(nullptr, this); //返回nullptr的正向迭代器
- }
- private:
- vector
_table; //哈希表 - size_t _n = 0; //哈希表中的有效元素个数
- };
- template<class K>
- class unordered_set
- {
- //仿函数
- struct SetKeyOfT
- {
- const K& operator()(const K& key) //返回键值key
- {
- return key;
- }
- };
-
- public:
-
- //现在没有实例化,没办法到HashTable里面找iterator,所以typename就是告诉编译器这里是一个类型,实例化以后再去取
- typedef typename HashTable
::iterator iterator; -
- iterator begin()
- {
- return _ht.begin();
- }
-
- iterator end()
- {
- return _ht.end();
- }
-
- //插入函数
- pair
bool > insert(const K& key) - {
- return _ht.Insert(key);
- }
-
- //删除函数
- void erase(const K& key)
- {
- _ht.Erase(key);
- }
-
- //查找函数
- iterator find(const K& key)
- {
- return _ht.Find(key);
- }
- private:
- HashTable
_ht; - };
- template<class K, class V>
- class unordered_map
- {
- //仿函数
- struct MapKeyOfT
- {
- const K& operator()(const pair
& kv) //返回键值对当中的键值key - {
- return kv.first;
- }
- };
-
- public:
- typedef typename HashTable
, MapKeyOfT>::iterator iterator; -
- iterator begin()
- {
- return _ht.begin();
- }
-
- iterator end()
- {
- return _ht.end();
- }
-
- //插入函数
- pair
bool > insert(const pair& kv) - {
- return _ht.Insert(kv);
- }
-
- //赋值运算符重载
- V& operator[](const K& key)
- {
- pair
bool> ret = insert(make_pair(key, V())); - iterator it = ret.first;
- return it->second;
- }
-
- //删除函数
- void erase(const K& key)
- {
- _ht.Erase(key);
- }
-
- //查找函数
- iterator find(const K& key)
- {
- return _ht.Find(key);
- }
-
- private:
- HashTable
, MapKeyOfT> _ht; - };
(1)哈希表的代码
- //哈希结点的定义
- template<class T>
- struct HashNode
- {
- T _data;
- HashNode
* _next; -
- //构造函数
- HashNode(const T& data)
- :_data(data)
- , _next(nullptr)
- {}
- };
-
- template<class K>
- struct Hash
- {
- size_t operator()(const K& key) //返回键值key
- {
- return key;
- }
- };
-
- //string类型的特化
- template<>
- struct Hash
- {
- size_t operator()(const string& s) //BKDRHash算法
- {
- size_t value = 0;
- for (auto ch : s)
- {
- value = value * 131 + ch;
- }
- return value;
- }
- };
-
-
- //哈希表的实现
- template<class K, class T, class KeyOfT, class HashFunc = Hash
> - class HashTable
- {
- //将正向迭代器类声明为哈希表类的友元
- template<class K, class T, class KeyOfT, class HashFunc>
- friend struct __HTIterator;
- //friend struct __HTIterator
; -
- typedef HashNode
Node; //哈希结点类型 -
- public:
- typedef __HTIterator
iterator; //正向迭代器的类型 -
- iterator begin()
- {
- size_t i = 0;
- while (i < _table.size()) //找到第一个非空哈希桶
- {
- if (_table[i]) //该哈希桶非空
- {
- return iterator(_table[i], this); //返回该哈希桶中的第一个结点的正向迭代器
- }
- i++;
- }
- return end(); //哈希桶中无数据,返回end()
- }
-
- iterator end()
- {
- return iterator(nullptr, this); //返回nullptr的正向迭代器
- }
-
- //构造函数
- HashTable() = default; //显示指定生成默认构造
-
- //拷贝构造函数
- HashTable(const HashTable& ht)
- {
- //1、将哈希表的大小调整为ht._table的大小
- _table.resize(ht._table.size());
-
- //2、将ht._table每个桶当中的结点一个个拷贝到自己的哈希表中(深拷贝)
- for (size_t i = 0; i < ht._table.size(); i++)
- {
- if (ht._table[i]) //桶不为空
- {
- Node* cur = ht._table[i];
- while (cur) //将该桶的结点取完为止
- {
- Node* copy = new Node(cur->_data); //创建拷贝结点
- //将拷贝结点头插到当前桶
- copy->_next = _table[i];
- _table[i] = copy;
- cur = cur->_next; //取下一个待拷贝结点
- }
- }
- }
- //3、更改哈希表当中的有效数据个数
- _n = ht._n;
- }
-
- //赋值运算符重载函数
- HashTable& operator=(HashTable ht)
- {
- //交换哈希表中两个成员变量的数据
- _table.swap(ht._table);
- swap(_n, ht._n);
-
- return *this; //支持连续赋值
- }
-
- //析构函数
- ~HashTable()
- {
- //将哈希表当中的结点一个个释放
- for (size_t i = 0; i < _table.size(); i++)
- {
- if (_table[i]) //桶不为空
- {
- Node* cur = _table[i];
- while (cur) //将该桶的结点取完为止
- {
- Node* next = cur->_next; //记录下一个结点
- delete cur; //释放结点
- cur = next;
- }
- _table[i] = nullptr; //将该哈希桶置空
- }
- }
- }
-
- //获取本次增容后哈希表的大小
- size_t GetNextPrime(size_t prime)
- {
- const int PRIMECOUNT = 28;
- //素数序列
- const size_t primeList[PRIMECOUNT] =
- {
- 53ul, 97ul, 193ul, 389ul, 769ul,
- 1543ul, 3079ul, 6151ul, 12289ul, 24593ul,
- 49157ul, 98317ul, 196613ul, 393241ul, 786433ul,
- 1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul,
- 50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul,
- 1610612741ul, 3221225473ul, 4294967291ul
- };
-
- size_t i = 0;
- for (i = 0; i < PRIMECOUNT; i++)
- {
- if (primeList[i] > prime)
- return primeList[i];
- }
- return primeList[i];
- }
-
- //插入函数
- pair
bool > Insert(const T& data) - {
- KeyOfT kot;
-
- //1、查看哈希表中是否存在该键值的键值对
- iterator ret = Find(kot(data));
- if (ret != end()) //哈希表中已经存在该键值的键值对(不允许数据冗余)
- {
- return make_pair(ret, false); //插入失败
- }
-
- //2、判断是否需要调整哈希表的大小
- if (_n == _table.size()) //哈希表的大小为0,或负载因子超过1
- {
- //增容
- //a、创建一个新的哈希表,新哈希表的大小设置为原哈希表的2倍(若哈希表大小为0,则将哈希表的初始大小设置为10)
- HashFunc hf;
- vector
newtable; - //size_t newsize = _table.size() == 0 ? 10 : _table.size() * 2;
- //newtable.resize(newsize);
-
- newtable.resize(GetNextPrime(_table.size()));
-
- //b、将原哈希表当中的结点插入到新哈希表
- for (size_t i = 0; i < _table.size(); i++)
- {
- if (_table[i]) //桶不为空
- {
- Node* cur = _table[i];
- while (cur) //将该桶的结点取完为止
- {
- Node* next = cur->_next; //记录cur的下一个结点
- size_t index = hf(kot(cur->_data))%newtable.size(); //通过哈希函数计算出对应的哈希桶编号index(除数不能是capacity)
-
- //将该结点头插到新哈希表中编号为index的哈希桶中
- cur->_next = newtable[index];
- newtable[index] = cur;
-
- cur = next; //取原哈希表中该桶的下一个结点
- }
- _table[i] = nullptr; //该桶取完后将该桶置空
- }
- }
- //c、交换这两个哈希表
- _table.swap(newtable);
- }
-
- //3、将键值对插入哈希表
- HashFunc hf;
- size_t index = hf(kot(data)) % _table.size(); //通过哈希函数计算出对应的哈希桶编号index(除数不能是capacity)
- Node* newnode = new Node(data); //根据所给数据创建一个待插入结点
-
- //将该结点头插到新哈希表中编号为index的哈希桶中
- newnode->_next = _table[index];
- _table[index] = newnode;
-
- //4、哈希表中的有效元素个数加一
- _n++;
- return make_pair(iterator(newnode, this), true);
- }
-
- //查找函数
- iterator Find(const K& key)
- {
- if (_table.size() == 0) //哈希表大小为0,查找失败
- {
- return end();
- }
-
- KeyOfT kot;
- HashFunc hf;
- size_t index = hf(key) % _table.size(); //通过哈希函数计算出对应的哈希桶编号index(除数不能是capacity)
-
- //遍历编号为index的哈希桶
- HashNode
* cur = _table[index]; - while (cur) //直到将该桶遍历完为止
- {
- if (kot(cur->_data) == key) //key值匹配,则查找成功
- {
- return iterator(cur, this);
- }
- cur = cur->_next;
- }
- return end(); //直到该桶全部遍历完毕还没有找到目标元素,查找失败
- }
-
- //删除函数
- bool Erase(const K& key)
- {
- KeyOfT kot;
- HashFunc hf;
- //1、通过哈希函数计算出对应的哈希桶编号index(除数不能是capacity)
- size_t index = hf(key) % _table.size();
-
- //2、在编号为index的哈希桶中寻找待删除结点
- Node* prev = nullptr;
- Node* cur = _table[index];
- while (cur) //直到将该桶遍历完为止
- {
- if (kot(cur->_data) == key) //key值匹配,则查找成功
- {
- //3、若找到了待删除结点,则删除该结点
- if (prev == nullptr) //待删除结点是哈希桶中的第一个结点
- {
- _table[index] = cur->_next; //将第一个结点从该哈希桶中移除
- }
- else //待删除结点不是哈希桶的第一个结点
- {
- prev->_next = cur->_next; //将该结点从哈希桶中移除
- }
- delete cur; //释放该结点
-
- //4、删除结点后,将哈希表中的有效元素个数减一
- _n--;
- return true; //删除成功
- }
- prev = cur;
- cur = cur->_next;
- }
- //假删除可能会导致迭代器失效
-
- return false; //直到该桶全部遍历完毕还没有找到待删除元素,删除失败
- }
- private:
- vector
_table; //哈希表 - size_t _n = 0; //哈希表中的有效元素个数
- };
(2)正向迭代器的代码
- //前置声明, HashTable和__HTIterator互相依赖
- template<class K, class T, class KeyOfT, class HashFunc>
- class HashTable;
-
- //正向迭代器
- template<class K, class T, class KeyOfT, class HashFunc = Hash
> - struct __HTIterator
- {
- typedef HashNode
Node; //哈希结点的类型 - typedef HashTable
HT; //哈希表的类型 - typedef __HTIterator
Self; //正向迭代器的类型 -
- Node* _node; //结点指针
- HT* _pht; //哈希表的地址
-
- //构造函数
- __HTIterator(Node* node, HT* pht)
- :_node(node) //结点指针
- , _pht(pht) //哈希表地址
- {}
-
- T& operator*()
- {
- return _node->_data; //返回哈希结点中数据的引用
- }
-
- T* operator->()
- {
- return &_node->_data; //返回哈希结点中数据的地址
- }
-
- bool operator!=(const Self& s) const
- {
- return _node != s._node; //判断两个结点的地址是否不同
- }
-
- bool operator==(const Self& s) const
- {
- return _node == s._node; //判断两个结点的地址是否相同
- }
-
- //前置++
- Self& operator++()
- {
- if (_node->_next) //该结点不是当前哈希桶中的最后一个结点
- {
- _node = _node->_next; //++后变为当前哈希桶中的下一个结点
- }
- else //该结点是当前哈希桶中的最后一个结点
- {
- KeyOfT kot;
- HashFunc hf;
- size_t index = hf(kot(_node->_data)) % _pht->_table.size(); //通过哈希函数计算出当前所处哈希桶编号index(除数不能是capacity)
-
- index++; //从下一个位置开始找一个非空的哈希桶
- while (index < _pht->_table.size()) //直到将整个哈希表找完
- {
- if (_pht->_table[index]) //当前哈希桶非空
- {
- _node = _pht->_table[index]; //++后变为当前哈希桶中的第一个结点
- return *this;
- }
- index++; //当前哈希桶为空桶,找下一个哈希桶
- }
- _node = nullptr; //哈希表中已经没有空桶了,++后变为nullptr
- }
- return *this;
- }
- };
(3)unordered_set的代码
- namespace XM //防止命名冲突
- {
- template<class K>
- class unordered_set
- {
- //仿函数
- struct SetKeyOfT
- {
- const K& operator()(const K& key) //返回键值key
- {
- return key;
- }
- };
- public:
- //现在没有实例化,没办法到HashTable里面找iterator,所以typename就是告诉编译器这里是一个类型,实例化以后再去取
- typedef typename HashTable
::iterator iterator; -
- iterator begin()
- {
- return _ht.begin();
- }
- iterator end()
- {
- return _ht.end();
- }
-
- //插入函数
- pair
bool > insert(const K& key) - {
- return _ht.Insert(key);
- }
-
- //删除函数
- void erase(const K& key)
- {
- _ht.Erase(key);
- }
-
- //查找函数
- iterator find(const K& key)
- {
- return _ht.Find(key);
- }
- private:
- HashTable
_ht; - };
- }
(4)unordered_map的代码
- namespace XM //防止命名冲突
- {
- template<class K, class V>
- class unordered_map
- {
- //仿函数
- struct MapKeyOfT
- {
- const K& operator()(const pair
& kv) //返回键值对当中的键值key - {
- return kv.first;
- }
- };
-
- public:
- typedef typename HashTable
, MapKeyOfT>::iterator iterator; -
- iterator begin()
- {
- return _ht.begin();
- }
- iterator end()
- {
- return _ht.end();
- }
-
- //插入函数
- pair
bool > insert(const pair& kv) - {
- return _ht.Insert(kv);
- }
-
- //赋值运算符重载
- V& operator[](const K& key)
- {
- pair
bool> ret = insert(make_pair(key, V())); - iterator it = ret.first;
- return it->second;
- }
-
- //删除函数
- void erase(const K& key)
- {
- _ht.Erase(key);
- }
-
- //查找函数
- iterator find(const K& key)
- {
- return _ht.Find(key);
- }
- private:
- HashTable
, MapKeyOfT> _ht; - };
- }