C++中Hash表
在C++中实现的Hash表为unordered_map和unordered_set这两个容器,其底层实现都是使用hash表实现的(关于hash表的详细细节和实现,这篇blog有讲解:Hash表(C++)_c++ hash表-blog),本篇将用该博客中提到的hash桶的方式实现unordered_map和unordered_set这两个容器,也就是使用模板将博客中的hash桶包装成这两个容器。
unordered_map中存放的是键值对,根据键值在hash桶中存放键值及其对应的值(key-value)。
unordered_set中只存放了键值(key)。
hash桶
在Hash表(C++)_c++ hash表-blog该博客中并没有实现hash桶的迭代器,为了实现unordered_map和unordered_set,还需要在hash桶的底层实现其迭代器,给unordered_map和unordered_set的迭代去造轮子。
全部代码如下(文件名:HashTable.h):
#pragma once
#include <vector>
#include <string>
#include <iostream>
using namespace std;
// hash函数的特化
template <class K>
struct HashFunc {
size_t operator()(const K& key) {
return (size_t)key;
}
};
template<>
struct HashFunc <string> {
size_t operator()(const string& key) {
size_t hash = 0;
for (auto e : key)
hash = hash * 131 + e;
return hash;
}
};
namespace Hash_Bucket {
// 节点
template<class K, class T>
struct HashNode {
T _data;
HashNode* _next = nullptr;
HashNode() = default;
HashNode(const T& data)
: _data(data)
, _next(nullptr)
{
}
};
// 前置声明hash桶
template <class K, class T, class KeyOfT, class Hash>
class HashTable;
/// <summary>
/// <typeparam name="K"></typeparam> key
/// <typeparam name="T"></typeparam> value
/// <typeparam name="Ref"></typeparam> 传入引用,因为是map和set的底层,他们会分别传入引用,所以需要单独设计出来
/// <typeparam name="Ptr"></typeparam> 传入指针,和引用同样的道理
/// <typeparam name="KeyOfT"></typeparam> 仿函数,operator()的返回值是map和key对应的key
/// <typeparam name="Hash"></typeparam> hash函数,也是由map和set分别传入
/// </summary>
template <class K, class T, class Ref, class Ptr, class KeyOfT, class Hash>
class __HTiterator {
typedef HashNode<K, T> Node;
typedef __HTiterator<K, T, Ref, Ptr, KeyOfT, Hash> Self;
typedef HashTable<K, T, KeyOfT, Hash> hashtable;
public:
__HTiterator()
: _node(nullptr)
, _pht(nullptr)
{
}
__HTiterator(Node* node, const hashtable* pht) {
_node = node;
_pht = pht;
}
bool operator!=(const Self& it) {
return _node != it._node;
}
Ref operator*() {
return _node->_data;
}
Ptr operator->() {
return &(_node->_data);
}
/// <summary>
/// hash表的迭代器是单向迭代器,所以只能++,前置++和后置++逻辑一样
/// 本篇就只实现后置++
/// </summary>
Self& operator++() {
// 若当前元素的下一个位置还存在元素,那么直接传递下一个元素
if (_node->_next) {
_node = _node->_next;
return *this;
}
Hash hf;
KeyOfT kot;
// 计算hash位置
size_t index = hf(kot(_node->_data)) % _pht->_tables.size();
++index;
for (size_t i = index; i < _pht->_tables.size(); i++) {
Node* cur = _pht->_tables[i];
if (cur != nullptr) {
_node = cur;
return *this;
}
}
// 走到这里就说明没有找到对应的元素,已经是最后一个
// 所以将迭代器指向nullptr
_node = nullptr;
return *this;
}
private:
// 存放结点指针和hash桶的指针
Node* _node;
const hashtable* _pht;
};
template <class K, class T, class KeyOfT, class Hash>
class HashTable {
typedef HashNode<K, T> Node;
// 将迭代器设置为友员
template <class K, class T, class Ref, class Ptr, class KeyOfT, class Hash >
friend class __HTiterator;
public:
typedef __HTiterator<K, T,