1 .模板参数列表的改造
- unordered_set是 K模型 的容器,unordered_map是 KV模型 的容器。
- 要想只用一份哈希表代码同时封装出K模型和KV模型的容器,我们就要对哈希表的模板参数进行控制。
- 为了与原哈希表的模板参数进行区分,这里将哈希表的第二个模板参数的名字改为T。
template<class K, class V, class KeyOfValue, class HF = DefHashF<T> >
class HashBucket;
- K:关键码类型
- V: 不同容器V的类型不同,如果是unordered_map,V代表一个键值对,如果是unordered_set,V 为 K
unordered_set:
template<class K>
class unordered_set
{
public:
//...
private:
//传入底层哈希表的是K和K
HashTable<K,const K> _ht;
};
unordered_map :注意这里V里面的K要加const,因为K是不可更改的
template<class K, class V>
class unordered_map
{
public:
//...
private:
HashTable<K, pair<const K, V>> _ht; //传入底层哈希表的是K以及K和V构成的键值对
};
- KeyOfValue: 因为V的类型不同,通过value取key的方式就不同,详细unordered_map/set的实现
- HF: 哈希函数仿函数对象类型,哈希函数使用除留余数法,需要将Key转换为整形数字才能取模
2 .增加迭代器
迭代器的结构:
有两个成员,一个是节点指针,还有一个是哈希表的指针,只要就是为了方便实现迭代器++遍历哈希表的操作。
模板参数列表的前四个class主要是为了实现普通迭代器和const迭代器,第五个参数就是为了获得T中的key值,是一个仿函数,最后一个模板参数是哈希函数,为了构造出哈希表指针而存在
迭代器基本操作的实现:
template<class K,class T,class Ref,class Ptr,class KeyOfT,class hash>
struct HashIterator
{
//重命名哈希节点
typedef HashData<T> Node;
//重命名迭代器
typedef HashIterator<K,T, Ref, Ptr, KeyOfT, hash> self;
//指向哈希节点的指针
Node* _node;
//指向哈希表的指针
HashTable<K, T, KeyOfT, hash>* _ht;
HashIterator(Node* node, HashTable<K, T, KeyOfT, hash>*ht) :_node(node),_ht(ht) {}
//解引用
Ref operator*()
{
return _node->_data;
}
//重载箭头
Ptr operator->()
{
return &_node->_data;
}
//前置加加
self& operator++()
{
if (_node->_next)
_node = _node->_next;
else
{
hash hs;
KeyOfT kot;
int hashi = hs(kot(_node->_data)) % _ht->_tables.size();
int i = hashi + 1;
for (; i < _ht->_tables.size(); i++)
{
if (_ht->_tables[i])
{
_node = _ht->_tables[i];
break;
}
}
if(_ht->_tables.size() == i)
_node = nullptr;
}
return *this;
}
//重载!=
bool operator!=(const self& l)
{
return _node != l._node;
}
};
哈希表内部改造:
template<class K,class T,class KeyOfT,class hash>
class HashTable
{
//注意这里需要声明友元才行
//因为迭代器里面有指向哈希表的指针
//这里可以采用内部内的方法
friend HashIterator<K, T, T&, T*, KeyOfT, hash>;
public:
//普通迭代器
typedef HashIterator<K, T, T&, T*, KeyOfT, hash> iterator;
//const迭代器
typedef HashIterator<K, T,const T&,const T*, KeyOfT, hash> const_iterator;
//节点指针
typedef HashData<T> Node;
//迭代器
HashTable(int n = 10)
{
_tables.resize(n,nullptr);
}
iterator begin()
{
for (int i = 0; i < _tables.size(); i++)
{
if (_tables[i])
return iterator(_tables[i],this);
}
return iterator(nullptr,this);
}
const_iterator begin()const
{
for (int i = 0; i < _tables.size(); i++)
{
if (_tables[i])
return iterator(_tables[i], this);
}
return iterator(nullptr, this);
}
iterator end()
{
return iterator(nullptr, this);
}
const_iterator end()const
{
return iterator(nullptr, this);
}
//插入
std::pair<iterator,bool> insert(const T& data)
{
KeyOfT kot;
iterator ret = Find(kot(data));
if(ret!=end())//这里的!=重载的时候必须加const
return std::make_pair(ret, false);
//哈希桶不需要线性探测,挂过去就行了
hash hs;
Node* newnode = new Node(data);
int hashi = hs(kot(data)) % _tables.size();
newnode->_next = _tables[hashi];
_tables[hashi] = newnode;
_n++;
//判断是否需要扩容
if (_n * 10 / _tables.size() > 8)
{
HashTable<K,T,KeyOfT,hash> newHT(_tables.size()*2);
//采用挪动节点的方法,减少消耗
for (auto& head : _tables)
{
Node* cur = head;
while (cur)
{
Node* next = cur->_next;
int hashi = hs(kot(cur->_data)) % newHT._tables.size();
cur->_next = newHT._tables[hashi];
newHT._tables[hashi] = cur;
cur = next;
}
head = nullptr;
}
_tables.swap(newHT._tables);
}
return std::make_pair(iterator(newnode, this), true);
}
iterator Find(const K& data)
{
hash hs;
KeyOfT kot;
int hashi = hs(data) % _tables.size();
if (_tables[hashi])
{
Node* cur = _tables[hashi];
while (cur)
{
if (kot(cur->_data) == data)return iterator(cur,this);
cur = cur->_next;
}
}
return iterator(nullptr,this);
}
//删除
bool Erase(const K& key)
{
hash hs;
KeyOfT kot;
int hashi = hs(key) % _tables.size();
if (_tables[hashi])
{
Node* cur = _tables[hashi];
Node* parent = nullptr;
while (cur)
{
if (kot(cur->_data) == key)
{
if (parent)
parent->_next = cur->_next;
else
_tables[hashi] = cur->_next;
delete cur;
cur = nullptr;
--_n;
return true;
}
parent = cur;
cur = cur->_next;
}
return false;
}
}
//析构
~HashTable()
{
for (auto head : _tables)
{
Node* cur = head;
while (cur)
{
Node* next = cur->_next;
delete cur;
cur = next;
}
head = nullptr;
}
}
private:
//这里用vector来存储节点(节点是用链表存储
std::vector<HashData<T>*> _tables;
int _n = 0;
};
3 . unordered_map
封装unordered_map:
template<class K>
//哈希函数,很多类型需要自己实现
struct HashFunc
{
size_t operator()(const K& key)
{
return size_t(key);
}
};
//string经常使用,搞一个特化版本
template<>
struct HashFunc<std::string>
{
size_t operator()(const std::string& str)
{
int hash = 0;
for (auto e : str)
{
hash *= 131;
hash += e;
}
return hash;
}
};
//使用unordered_map需要传入哈希函数,也有类型是默认的
template<class K, class V, class hash = HashFunc<K>>
class unordered_map
{
public:
//用来取比较大小的key
struct KeyOfT
{
const K& operator()(const std::pair<const K, V>& d)
{
return d.first;
}
};
typedef typename HashTable<K, std::pair<const K, V>, KeyOfT, hash>::iteratiterator;
//这里不认识iterator是因为没有实例化
//编译器不知道他是类还是什么
//加tepename是为了告诉编译器他是一个类型
typedef typename HashTable<K, const K, KeyOfT, hash>::const_iterator const_iterator;
iterator begin()
{
return _ht.begin();
}
iterator end()
{
return _ht.end();
}
const_iterator begin()const
{
return _ht.begin();
}
const_iterator end()const
{
return _ht.end();
}
//实现插入
std::pair<iterator, bool> insert(const std::pair<K, V>& data)
{
auto ret = _ht.insert(data);
return ret;
}
bool erase(const K& key)
{
return _ht.Erase(key);
}
//重载[]
//没有就插入并返回——值
//有就返回——值
V& operator[](const K& key)
{
auto ret = _ht.insert(std::make_pair(key, V()));
return ret.first->second;
}
//查找返回迭代器
iterator find(const K& key)
{
return _ht.Find(key);
}
private:
HashTable<K, std::pair<const K, V>, KeyOfT, hash> _ht;
};
4 . unordered_set
封装unordered_set:与上面unordered_map类似
template<class K>
struct HashFunc
{
size_t operator()(const K& key)
{
return size_t(key);
}
};
template<>
struct HashFunc<std::string>
{
size_t operator()(const std::string& str)
{
int hash = 0;
for (auto e : str)
{
hash *= 131;
hash += e;
}
return hash;
}
};
template<class K, class hash = HashFunc<K>>
class unordered_set
{
struct KeyOfT
{
const K& operator()(const K& key)
{
return key;
}
};
public:
typedef typename HashTable<K, const K, KeyOfT, hash>::iterator iterator;
typedef typename HashTable<K, const K, KeyOfT, hash>::const_iterator const_iterator;
iterator begin()
{
return _ht.begin();
}
iterator end()
{
return _ht.end();
}
const_iterator begin()const
{
return _ht.begin();
}
const_iterator end()const
{
return _ht.end();
}
std::pair<iterator, bool> insert(const K& key)
{
return _ht.insert(key);
}
bool erase(const K& key)
{
return _ht.Erase(key);
}
iterator find(const K& key)
{
return _ht.Find(key);
}
private:
HashTable<K, const K, KeyOfT, hash> _ht;
};