1.底层哈希(链地址)
template<class T>
struct HashNode
{
HashNode<T> _next;
T _data;
HashNode(const T& data = T())
:_next(nullptr)
, _data(data)
{}
};
2.成员变量
template<class K, class T, class KeyOfT, class HF>
class HashTable;
template<class K,class T, class Ref,class Ptr,class KeyOfT, class HF>
struct HashIterator
{
typedef HashNode<T> Node;
typedef HashIterator<K, T, Ref, Ptr, KeyOfT, HF> self;
typedef HashIterator<K, T, T&, T*, KeyOfT, HF> iterator;
typedef HashTable<K, T, KeyOfT, HF> HT;
Node* _node;
HT* _ht;//走到头之后要找的下一个节点
};
3.简单函数
HashIterator(Node*&node=nullptr,Node*&ht=nullptr)
:_node(node)
,_ht(ht)
{}
HashIterator(const iterator&it)
:_node(it._node)
, _ht(it._ht)
{}
Ref& operator*()const
{
return _node->_data;
}
Ptr& operator->()const
{
return &(_node->_data);
}
bool operator==(const self&se)
{
return _node == se._node;
}
bool operator!=(const self& se)
{
return _node != se._node;
}
左右++
1.下一个节点为空则下一位
2.为空则取模算出哈希地址,再线性探测
self& operator++()
{
Node* node = _node;
if (node->_next)
{
_node = node->_next;
return *this;
}
else
{
KeyOfT kot;
size_t hash = HF(kot(_node->_data)) % _ht->_tables.size()+1;
for (hash; hash < _ht->_tables.size(); hash++)
{
if (_ht->tables[hash])
{
_node = _ht->tables[hash];
return *this;
}
}
_node = nullptr;
return *this;
}
}
self operator++(int)
{
self new_self=*this;
(*this)++;
return new_self;
}
后置++就是调用前置++
哈希表
template<class K, class T, class KeyOfT, class HF>
class HashTable
{
template<class K, class T, class Ref, class Ptr, class KeyOfT, class HF>
friend struct HashIterator;
typedef HashNode<T> Node;
public:
protected:
vector<Node*> _tables;
size_t _size = 0;//有效数据个数
};
迭代器要返回私有成员,所以要声明友元
KEYOFT是分别封装map和set类型
模板参数HF即是HashFunc,哈希函数,用于辅助键值转化为整型进行取模操作
构造和析构
HashTable(size_t size = 10)
{
_tables.resize(size);
}
~HashTable()
{
for (auto hash_node : _tables)
{
while (hash_node)
{
Node* new_node = hash_node->_next;
delete hash_node;
hash_node = new_node;
}
}
}
begin和end
begin返回最开始不为空的哈希桶的迭代器,而不是最开始的哈希桶的迭代器
end返回空迭代器
构造迭代器需要传入哈希表本身的地址,这里直接传this指针即可
typedef HashIterator< K,T, T&, T*, KeyOfT, HF> iterator;
typedef HashIterator< K, T, const T&, const T*, KeyOfT, HF> const_iterator;
iterator begin()
{
for (size_t i = 0; i < _tables.size(); i++)
if (_tables[i])
return iterator(_tables[i], this);
return iterator(nullptr, this);
}
const_iterator begin()const
{
for (size_t i = 0; i < _tables.size(); i++)
if (_tables[i])
return const_iterator(_tables[i], this);
return const_iterator(nullptr, this);
}
iterator end()
{
return iterator(nullptr, this);
}
const_iterator end()
{
return const_iterator(nullptr, this);
}
find
返回类型是迭代器,运用一个仿函数来寻找
iterator Find(const K&key)
{
HF hf;
KeyOfT kot;
size_t hash = hf(key) % _tables.size();
Node* cur = _tables[hash];
while (cur)
{
if (kot(cur->_data) == key)
return iterator(cur,_tables);
cur = cur->_next;
}
return iterator(nullptr,_tables);
}
insert
如果空间不够就扩容,返回类型为pair,第一个是迭代器,第二个是bool
pair<iterator,bool> Insert(T& data)
{
KeyOfT kot;
HF hf;
iterator it = Find(kot(data));
if (it._node)
{
return make_pair(it, false);
}
if (_size == _tables.size())
{
vector<Node*> new_tables(_size * 2);
for (auto node : _tables)
{
while (node)
{
Node* next = node->_next;
size_t hash = hf(kot(node->_data)) % new_tables.size();
node->_next = new_tables[hash];
new_tables[hash] = node;
node = next;
}
}
_tables.swap(new_tables);
}
size_t hash = hf(kot(data)) % _tables.size();
Node* cur = _tables[hash];
Node* p(data);
p->_next = cur;
_tables[hash] = p;
_size++;
return make_pair(iterator(p,this),true);
}
erase
bool Erase(const K& key)
{
HF hf;
KeyOfT kot;
size_t hash = hf(key) % _tables.size();
Node* cur = _tables[hash];
Node* pre = nullptr;
while (cur)
{
if (kot(cur->data) == key)
break;
pre = cur;
cur = cur->_next;
}
if (cur == nullptr)
return false;
_size--;
if (pre == nullptr)
_tables[hash] = cur->_next;
else
pre->_next = cur->_next;
delete cur;
return true;
}
unorered_set
成员变量和仿函数
template<class K,class HF=HashFunc<K>>
class unordered_set
{
public:
struct SetKeyOfT
{
K& operator()(const K& key)
{
return key;
}
};
protected:
HashTable<K, K, SetKeyOfT, HF> _hf;
};
1.SETKEYOFT直接返回T
2.哈希函数可以自己写
begin和end
typedef typename HashTable<K, K, SetKeyOfT, HF>::iterator iterator;
typedef typename HashTable<K, K, SetKeyOfT, HF>::const_iterator const_iterator;
iterator begin()
{
return _ht.begin();
}
const_iterator begin()const
{
return _ht.begin();
}
iterator end()
{
return _ht.end();
}
const_iterator end()const
{
return _ht.end();
}
在c++中,iterator默认为变量名,如果要作为类型名则需要在前面加上typename加上typename关键字
由于key不能修改,所以普通和const迭代器均为const迭代器
我们称set的begin为A,哈希的begin为B,A的实现是对B的调用,在A的参数是普通迭代器时,B也是普通迭代器,B的返回值也是普通迭代器,但A的返回值是const迭代器,所以这里需要用普通迭代器创建一个const迭代器的临时变量,这就用到之前写的拷贝构造函数了
find
也有普通向const的转换
iterator Find(const K&key)
{
return _ht.Find(key);
}
insert
pair<iterator, bool> Insert(const K& key)
{
return _ht.Insert(key);
}
erase
bool Erase(const K& key)
{
return _ht.Erase(key);
}
unordered_map
成员变量和仿函数
template<class K,class V,class HF=HashFunc<K>>
class unordered_map
{
struct MapKeyOfT
{
const K& operator()(const pair<K, V>&kv)
{
return kv.first;
}
};
protected:
HashTable<K, pair<const K, V>, MapKeyOfT, HF> _ht;
};
begin和end
typedef typename HashTable<K, pair<K,V>, MapKeyOfT, HF>::iterator iterator;
typedef typename HashTable<K, pair<K,V>, MapKeyOfT, HF>::const_iterator const_iterator;
iterator begin()
{
return _ht.begin();
}
const_iterator begin()const
{
return _ht.begin();
}
iterator end()
{
return _ht.end();
}
const_iterator end()const
{
return _ht.end();
}
1.加上typename关键字,编译器才能识别类型
2.unordered_map不允许修改key,故普通迭代器和const的pair中的K都要加上const修饰,但是允许修改存储的data,所以普通和const迭代器一一对应
find
iterator Find(const K& key)
{
return _ht.Find(key);
}
insert
pair<iterator, bool> Insert(const pair<const K, V>& kv)
{
return _ht.Insert(kv);
}
operator[]
V& operator[](const& K key)
{
return (*(_ht.Insert(make_pair(key, V()))).first).second;
}
//或者你也可以这么写
V& operator[](const K& key)
{
pair<iterator, bool> cur = insert(make_pair(key, V()));
return cur.first->second;
}
返回值是value的引用,我们可以直接进行修改
erase
bool Erase(const K& key)
{
return _ht.Erase(key);
}