目录
前言
接着【C++】哈希表的实现详情请点击,今天继续介绍【C++】用哈希表封装myunordered_map和 myunordered_set
本次myunordered_map和 myunordered_set的介绍是在学习了解了【C++】哈希表的实现详情请点击查看以及【C++】STL----封装红黑树实现map和set详情请点击查看的基础上展开介绍的
一、源码及框架分析
- SGI-STL30版本源代码中没有unordered_map和unordered_set,SGI-STL30版本是C++11之前的STL版本,这两个容器是C++11之后才更新的
- SGI-STL30实现了哈希表,只容器的名字是hash_map和hash_set,他是作为非标准的容器出现的,非标准是指非C++标准规定必须实现的,源代码在
hash_map/hash_set/stl_hash_map/stl_hash_set/stl_hashtable.h中 - hash_map和hash_set的实现结构框架核心部分
cpp
// stl_hash_set
template <class Value, class HashFcn = hash<Value>, class EqualKey = equal_to<Value>, class Alloc = alloc>
class hash_set
{
private:
typedef hashtable<Value, Value, HashFcn, identity<Value>,
EqualKey, Alloc> ht;
ht rep;
public:
typedef typename ht::key_type key_type;
typedef typename ht::value_type value_type;
typedef typename ht::hasher hasher;
typedef typename ht::key_equal key_equal;
typedef typename ht::const_iterator iterator;
typedef typename ht::const_iterator const_iterator;
hasher hash_funct() const { return rep.hash_funct(); }
key_equal key_eq() const { return rep.key_eq(); }
};
// stl_hash_map
template <class Key, class T, class HashFcn = hash<Key>, class EqualKey = equal_to<Key>, class Alloc = alloc>
class hash_map
{
private:
typedef hashtable<pair<const Key, T>, Key, HashFcn,
select1st<pair<const Key, T> >, EqualKey, Alloc> ht;
ht rep;
public:
typedef typename ht::key_type key_type;
typedef T data_type;
typedef T mapped_type;
typedef typename ht::value_type value_type;
typedef typename ht::hasher hasher;
typedef typename ht::key_equal key_equal;
typedef typename ht::iterator iterator;
typedef typename ht::const_iterator const_iterator;
};
// stl_hashtable.h
template <class Value, class Key, class HashFcn, class ExtractKey, class EqualKey, class Alloc>
class hashtable {
public:
typedef Key key_type;
typedef Value value_type;
typedef HashFcn hasher;
typedef EqualKey key_equal;
private:
hasher hash;
key_equal equals;
ExtractKey get_key;
typedef __hashtable_node<Value> node;
vector<node*,Alloc> buckets;
size_type num_elements;
public:
typedef __hashtable_iterator<Value, Key, HashFcn, ExtractKey, EqualKey,
Alloc> iterator;
pair<iterator, bool> insert_unique(const value_type& obj);
const_iterator find(const key_type& key) const;
};
template <class Value>
struct __hashtable_node
{
__hashtable_node* next;
Value val;
};
- 通过源码可以看到,结构上hash_map和hash_set跟map和set的完全类似,复用同一个hashtable实现key和key/value结构,hash_set传给hash_table的是两个key,hash_map传给hash_table的是pair<const key,value>
二、unordered_map和unordered_set的实现
- 首先将哈希表的实现部分的哈希桶实现代码外层进行修改
- 哈希节点的模板传入的参数不再是一个确定的class T,class V的结构,而是传入一个T类型(可能是key,也可能是pair类型的key/value)
cpp
// Note: assumes long is at least 32 bits.
static const int __stl_num_primes = 28;
static const unsigned long __stl_prime_list[__stl_num_primes] =
{
53, 97, 193, 389, 769,
1543, 3079, 6151, 12289, 24593,
49157, 98317, 196613, 393241, 786433,
1572869, 3145739, 6291469, 12582917, 25165843,
50331653, 100663319, 201326611, 402653189, 805306457,
1610612741, 3221225473, 4294967291
};
inline unsigned long __stl_next_prime(unsigned long n)
{
const unsigned long* first = __stl_prime_list;
const unsigned long* last = __stl_prime_list + __stl_num_primes;
const unsigned long* pos = lower_bound(first, last, n);
return pos == last ? *(last - 1) : *pos;
}
template<class K>
struct HashFunc
{
size_t operator()(const K& key)
{
return (size_t)key;
}
};
//string特化
template<>
struct HashFunc<string>
{
size_t operator()(const string& key)
{
size_t hashi = 0;
for (auto& ch : key)
{
hashi *= 131;
hashi += ch;
}
return hashi;
}
};
namespace hash_bucket
{
template<class T>
struct HashNode
{
T _data;
HashNode<T>* _next;
HashNode(const T& data)
:_data(data)
, _next(nullptr)
{}
};
template<class K, class T, class Hash = HashFunc<K>>
class HashTable
{
typedef HashNode<T> Node;
public:
HashTable(size_t size = __stl_next_prime(0))
:_tables(size, nullptr)
{
}
~HashTable()
{
for (size_t i = 0; i < _tables.size(); i++)
{
Node* cur = _tables[i];
while (cur)
{
Node* next = cur->_next;
delete cur;
cur = next;
}
_tables[i] = nullptr;
}
}
bool Insert(const pair<K, V>& kv)
{
if (Find(kv.first))
return false;
Hash hs;
//负载因子为1再扩容
if (_n == _tables.size())
{
vector<Node*> newtables(__stl_next_prime(_tables.size() + 1), nullptr);
for (size_t i = 0; i < _tables.size(); i++)
{
Node* cur = _tables[i];
while (cur)
{
//旧表节点拿下来,插入到新表的位置
Node* next = cur->_next;
size_t hashi = hs(cur->_kv.first) % newtables.size();
cur->_next = newtables[hashi];
newtables[hashi] = cur;
cur = next;
}
_tables[i] = nullptr;
}
_tables.swap(newtables);
}
size_t hashi = hs(kv.first) % _tables.size();
//头插
Node* newnode = new Node(kv);
newnode->_next = _tables[hashi];
_tables[hashi] = newnode;
++_n;
return true;
}
Node* Find(const K& key)
{
Hash hs;
size_t hashi = hs(key) % _tables.size();
Node* cur = _tables[hashi];
while (cur)
{
if (cur->_kv.first == key)
return cur;
cur = cur->_next;
}
return nullptr;
}
bool Erase(const K& key)
{
Hash hs;
size_t hashi = hs(key) % _tables.size();
Node* cur = _tables[hashi];
Node* prev = nullptr;
while (cur)
{
if (cur->_kv.first == key)
{
if (prev == nullptr)
{
_tables[hashi] = cur->_next;
}
else
{
prev->_next = cur->_next;
}
--_n;
delete cur;
return true;
}
prev = cur;
cur = prev->_next;
}
return false;
}
private:
vector<Node*> _tables; //指针数组
size_t _n = 0;
};
};
- 添加UnorderedMap.h,UnorderedSet.h,并包含HashTable.h头文件,并将UnorderedMap,UnorderedSet框架搭出来
- UnorderedMap,UnorderedSet底层就是依靠哈希桶实现的
cpp
//UnorderedSet.h
namespace gy
{
template<class K>
class unordered_set
{
public:
private:
hash_bucket::HashTable<K, K> _ht;
};
}
//UnorderedMap.h
namespace gy
{
template<class K, class V>
class unordered_map
{
public:
private:
hash_bucket::HashTable<K, pair<K, V>> _ht;
};
}
insert
- UnorderedSet和UnorderedMap的insert实现和map/set一样外层并没有具体实现方法,而是调用底层Insert算法。
cpp
//UnorderedSet.h
namespace gy
{
template<class K>
class unordered_set
{
public:
bool insert(const K& key)
{
_ht.Insert(key);
}
private:
hash_bucket::HashTable<K, K> _ht;
};
}
//UnorderedMap.h
namespace gy
{
template<class K, class V>
class unordered_map
{
public:
bool insert(const pair<K, V>& kv)
{
_ht.Insert(kv);
}
private:
hash_bucket::HashTable<K, pair<K, V>> _ht;
};
}
- 修改哈希桶的Insert算法,现在我们传入的数据类型不确定了,因此Insert的实现上也需要进行相应的修改
- 从上面Insert的代码中我们可以发现,Insert中有Find函数需要key值,且插入哈希桶位置的计算也需要key值,但是我们现在传入参数有可能是key,也可能是pair类型,因此我们需要将key值提取出来
- 在map/set的实现过程中也遇到过同样的问题,因此我们还是采用map和set层分别实现一个MapKeyOfT和SetKeyOfT的仿函数传给RBTree的KeyOfT,然后RBTree中通过KeyOfT仿函数取出T类型对象中的key,再进行比较的方法,来实现去除T类型中的key
cpp
//UnorderedSet.h
namespace gy
{
template<class K>
class unordered_set
{
public:
struct SetKeyOfT
{
const K& operator()(const K& key)
{
return key;
}
};
bool insert(const K& key)
{
_ht.Insert(key);
}
private:
hash_bucket::HashTable<K, K, SetKeyOfT> _ht;
};
}
//UnorderedMap.h
namespace gy
{
template<class K, class V>
class unordered_map
{
public:
struct MapKeyOfT
{
const K& operator()(const pair<K, V>& kv)
{
return kv.first;
}
};
bool insert(const pair<K, V>& kv)
{
_ht.Insert(kv);
}
private:
hash_bucket::HashTable<K, pair<K, V>, MapKeyOfT> _ht;
};
}
- 同时Find函数也是一样需要将key值取出进行比较查找
cpp
bool Insert(const T& data)
{
KeyOfT kot;
if(Find(kot(data)))
return false;
Hash hs;
//负载因子为1再扩容
if (_n == _tables.size())
{
vector<Node*> newtables(__stl_next_prime(_tables.size() + 1), nullptr);
for (size_t i = 0; i < _tables.size(); i++)
{
Node* cur = _tables[i];
while (cur)
{
//旧表节点拿下来,插入到新表的位置
Node* next = cur->_next;
size_t hashi = hs(kot(cur->_data)) % newtables.size();
cur->_next = newtables[hashi];
newtables[hashi] = cur;
cur = next;
}
_tables[i] = nullptr;
}
_tables.swap(newtables);
}
size_t hashi = hs(kot(data)) % _tables.size();
//头插
Node* newnode = new Node(data);
newnode->_next = _tables[hashi];
_tables[hashi] = newnode;
++_n;
return true;
}
Node* Find(const K& key)
{
Hash hs;
KeyOfT kot;
size_t hashi = hs(key) % _tables.size();
Node* cur = _tables[hashi];
while (cur)
{
if (kot(cur->_data)== key)
return cur;
cur = cur->_next;
}
return nullptr;
}
最终运行结果如下图所示
支持iterator、const_iterator的实现
- iterator实现的大框架跟list的iterator思路是一致的,用一个类型封装结点的指针,再通过重载运算符实现,迭代器像指针一样访问的行为,要注意的是哈希表的迭代器是单向迭代器
cpp
//源码
template <class Value, class Key, class HashFcn, class ExtractKey, class EqualKey, class Alloc>
struct __hashtable_iterator {
typedef hashtable<Value, Key, HashFcn, ExtractKey, EqualKey, Alloc>
hashtable;
typedef __hashtable_iterator<Value, Key, HashFcn, ExtractKey, EqualKey, Alloc> iterator;
typedef __hashtable_const_iterator<Value, Key, HashFcn, ExtractKey, EqualKey, Alloc> const_iterator;
typedef __hashtable_node<Value> node;
typedef forward_iterator_tag iterator_category;
typedef Value value_type;
node* cur;
hashtable* ht;
__hashtable_iterator(node* n, hashtable* tab) : cur(n), ht(tab) {}
__hashtable_iterator() {}
reference operator*() const { return cur->val; }
#ifndef __SGI_STL_NO_ARROW_OPERATOR
pointer operator->() const { return &(operator*()); }
#endif /* __SGI_STL_NO_ARROW_OPERATOR */
iterator& operator++();
iterator operator++(int);
bool operator==(const iterator& it) const { return cur == it.cur; }
bool operator!=(const iterator& it) const { return cur != it.cur; }
};
template <class V, class K, class HF, class ExK, class EqK, class A>
__hashtable_iterator<V, K, HF, ExK, EqK, A>& __hashtable_iterator<V, K, HF, ExK, EqK, A>::operator++()
{
const node* old = cur;
cur = cur->next;
if (!cur) {
size_type bucket = ht->bkt_num(old->val);
while (!cur && ++bucket < ht->buckets.size())
cur = ht->buckets[bucket];
}
return *this;
}
iterator实现
- operator++的实现。iterator中有一个指向结点的指针,如果当前桶下面还有结点,
则结点的指针指向下⼀个结点即可。如果当前桶走完了,则需要想办法计算找到下一个桶 。这里的难点是反而是结构设计的问题,参考上面的源码,我们可以看到iterator中除了有结点的指针,还有哈希表对象的指针,这样当前桶走完了,要计算下一个桶就相对容易多了,用key值计算出当前桶位置,依次往后找下一个不为空的桶即可 - 同时需要注意,编译器编译的时候只会向上查找,HTIterator使用了HashTable,因此需要在HTIterator前声明HashTable
- 在类外面,无法访问到类的私有成员变量,我们可以实现一个get函数来获得私有成员变量,还有一种方法就是友元,模板声明友元需要将模板参数带上
- begin()返回第一个桶中第一个节点指针构造的迭代器,这里end()返回迭代器可以用空表示
cpp
//HashTable.h
//前置声明
template<class K, class T, class KeyOfT, class Hash>
class HashTable;
template<class K, class T, class KeyOfT, class Hash>
struct HTIterator
{
typedef HashNode<T> Node;
typedef HashTable<K, T, KeyOfT, Hash> HT;
typedef HTIterator<K, T, KeyOfT, Hash> Self;
Node* _node; //节点指针
HT* _ht; //哈希表指针
HTIterator(Node* node, HT* ht)
:_node(node)
,_ht(ht)
{ }
T& operator*()
{
return _node->_data;
}
T* operator->()
{
return &_node->_data;
}
Self& operator++()
{
if (_node->_next)
{
_node = _node->_next;
}
else
{
KeyOfT kot;
Hash hs;
size_t hashi = hs(kot(_node->_data)) % _ht->_tables.size();
++hashi;
while(hashi < _ht->_tables.size())
{
if (_ht->_tables[hashi])
{
_node = _ht->_tables[hashi];
break;
}
++hashi;
}
if (hashi == _ht->_tables.size())
_node = nullptr;
}
return *this;
}
bool operator != (const Self& s)
{
return _node != s._node;
}
bool operator == (const Self& s)
{
return _node == s._node;
}
};
template<class K, class T,class KeyOfT, class Hash = HashFunc<K>>
class HashTable
{
template<class K, class T, class KeyOfT, class Hash>
friend struct HTIterator;
typedef HashNode<T> Node;
public:
typedef HTIterator<K, T, KeyOfT, Hash> Iterator;
Iterator Begin()
{
for (size_t i = 0; i < _tables.size(); i++)
{
if (_tables[i])
return Iterator(_tables[i], this);
}
return End();
}
Iterator End()
{
return Iterator(nullptr, this);
}
//......
};
- 注意:typedef取类模板中的内嵌类型时,由于类模板没有实例化,因此不确定是类型还是静态成员变量,因此需要加上typename ,还可以使用using关键字
cpp
//UnorderedSet.h
namespace gy
{
template<class K>
class unordered_set
{
public:
struct SetKeyOfT
{
const K& operator()(const K& key)
{
return key;
}
};
typedef typename hash_bucket::HashTable<K, K, SetKeyOfT> ::Iterator iterator;
iterator begin()
{
return _ht.Begin();
}
iterator end()
{
return _ht.End();
}
bool insert(const K& key)
{
return _ht.Insert(key);
}
private:
hash_bucket::HashTable<K, K, SetKeyOfT> _ht;
};
}
//UnorderedMap.h
namespace gy
{
template<class K, class V>
class unordered_map
{
public:
struct MapKeyOfT
{
const K& operator()(const pair<K, V>& kv)
{
return kv.first;
}
};
//typedef typename hash_bucket::HashTable<K, pair<K, V>, MapKeyOfT> ::Iterator iterator;
using iterator = typename hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT, Hash> ::Iterator;
iterator begin()
{
return _ht.Begin();
}
iterator end()
{
return _ht.End();
}
bool insert(const pair<K, V>& kv)
{
return _ht.Insert(kv);
}
private:
hash_bucket::HashTable<K, pair<K, V>, MapKeyOfT> _ht;
};
}
测试
cpp
void test()
{
gy::unordered_map<string, string> map;
gy::unordered_set<int> set;
int a[] = { 19, 30, 5, 36, 13, 20, 21, 12 };
for (auto e : a)
set.insert(e);
map.insert({ "left", "左边" });
map.insert({ "right", "右边" });
map.insert({ "sort", "排序" });
for (auto e : set)
cout << e << " ";
cout << endl;
for (auto ch : map)
cout << ch.first << " " << ch.second << endl;
}

const_iterator实现
- 和list的const_iterator实现一样,我们需要在上面的iterator的基础上添加两个参数,Ref和Ptr来控制传入的类型是可修改的还是const修饰的不可修改的
cpp
//HashTable.h
template<class K, class T, class Ref, class Ptr, class KeyOfT, class Hash>
struct HTIterator
{
typedef HashNode<T> Node;
typedef HashTable<K, T, KeyOfT, Hash> HT;
typedef HTIterator<K, T, Ref, Ptr, KeyOfT, Hash> Self;
Node* _node; //节点指针
HT* _ht; //哈希表指针
HTIterator(Node* node, HT* ht)
:_node(node)
,_ht(ht)
{ }
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 hashi = hs(kot(_node->_data)) % _ht->_tables.size();
++hashi;
while(hashi < _ht->_tables.size())
{
if (_ht->_tables[hashi])
{
_node = _ht->_tables[hashi];
break;
}
++hashi;
}
if (hashi == _ht->_tables.size())
_node = nullptr;
}
return *this;
}
bool operator != (const Self& s)
{
return _node != s._node;
}
bool operator == (const Self& s)
{
return _node == s._node;
}
};
template<class K, class T,class KeyOfT, class Hash = HashFunc<K>>
class HashTable
{
template<class K, class T, class Ref, class Ptr, class KeyOfT, class Hash>
friend struct HTIterator;
typedef HashNode<T> Node;
public:
typedef HTIterator<K, T, T&, T*, KeyOfT, Hash> Iterator;
typedef HTIterator<K, T, const T&, const T*, KeyOfT, Hash> Const_Iterator;
Iterator Begin()
{
for (size_t i = 0; i < _tables.size(); i++)
{
if (_tables[i])
return Iterator(_tables[i], this);
}
return End();
}
Iterator End()
{
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 End();
}
Const_Iterator End()const
{
return Const_Iterator(nullptr, this);
}
//....
};
- 问题:上述代码编译报错,显示const迭代器没有重载函数可以转换的所有参数类型
- 原因以及解决办法:迭代器初始化时传入的哈希表指针是HT*类型,但是const_iterator迭代器是被const修饰的(修饰的就是哈希表指针),const修饰的变量传给普通变量权限放大,因此编译无法通过。
- 因此我们将迭代器哈希表的初始化使用const修饰,这样const和普通哈希表指针都能初始化
cpp
template<class K, class T, class Ref, class Ptr, class KeyOfT, class Hash>
struct HTIterator
{
typedef HashNode<T> Node;
typedef HashTable<K, T, KeyOfT, Hash> HT;
typedef HTIterator<K, T, Ref, Ptr, KeyOfT, Hash> Self;
Node* _node; //节点指针
const HT* _ht; //哈希表指针
HTIterator(Node* node, const HT* ht)
:_node(node)
,_ht(ht)
{ }
//.....
};

key不支持修改问题
- unordered_set的iterator不支持修改,我们把unordered_set的第二个模板参数改成const K即可,
HashTable<K, const K, SetKeyOfT, Hash> _ht;unordered_map的iterator不支持修改key但是可以修改value,我们把unordered_map的第二个模板参数pair的第一个参数改成const K即可,HashTable<K, pair<const K, V>, MapKeyOfT, Hash> _ht
cpp
//UnorderedSet.h
namespace gy
{
template<class K>
class unordered_set
{
public:
struct SetKeyOfT
{
const K& operator()(const K& key)
{
return key;
}
};
typedef typename hash_bucket::HashTable<K, const K, SetKeyOfT> ::Iterator iterator;
typedef typename hash_bucket::HashTable<K, const K, SetKeyOfT> ::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();
}
bool insert(const K& key)
{
return _ht.Insert(key);
}
private:
hash_bucket::HashTable<K, const K, SetKeyOfT> _ht;
};
}
//UnorderedMap.h
namespace gy
{
template<class K, class V>
class unordered_map
{
public:
struct MapKeyOfT
{
const K& operator()(const pair<K, V>& kv)
{
return kv.first;
}
};
typedef typename hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT> ::Iterator iterator;
typedef typename hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT> ::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();
}
bool insert(const pair<K, V>& kv)
{
return _ht.Insert(kv);
}
private:
hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT> _ht;
};
}
map支持[]
- map支持[],其本质底层是需要调用insert来实现,因此我们需要将我们上面的Insert函数进行修改,使其返回值是一个pair类型(
pair<Iterator, bool>),因为Insert函数中使用了Find函数,因此Find函数也需要进行修改,返回值为Iterator类型
cpp
//HashTable.h
pair<Iterator, bool> Insert(const T& data)
{
KeyOfT kot;
Iterator it = Find(kot(data));
if(it != End())
{
return {it, false};
}
Hash hs;
//负载因子为1再扩容
if (_n == _tables.size())
{
vector<Node*> newtables(__stl_next_prime(_tables.size() + 1), nullptr);
for (size_t i = 0; i < _tables.size(); i++)
{
Node* cur = _tables[i];
while (cur)
{
//旧表节点拿下来,插入到新表的位置
Node* next = cur->_next;
size_t hashi = hs(kot(cur->_data)) % newtables.size();
cur->_next = newtables[hashi];
newtables[hashi] = cur;
cur = next;
}
_tables[i] = nullptr;
}
_tables.swap(newtables);
}
size_t hashi = hs(kot(data)) % _tables.size();
//头插
Node* newnode = new Node(data);
newnode->_next = _tables[hashi];
_tables[hashi] = newnode;
++_n;
return { {newnode, this}, true };
}
Iterator Find(const K& key)
{
Hash hs;
KeyOfT kot;
size_t hashi = hs(key) % _tables.size();
Node* cur = _tables[hashi];
while (cur)
{
if (kot(cur->_data)== key)
return Iterator(cur, this);
cur = cur->_next;
}
return End();
}
////UnorderedMap.h
V& operator[](const K& key)
{
pair<iterator, bool> ret = _ht.Insert({key, V()});
return ret.first->second;
}
测试
cpp
void test2()
{
gy::unordered_map<string, string> map;
map.insert({ "left", "左边" });
map.insert({ "right", "右边" });
map.insert({ "sort", "排序" });
map["123"]; //新插入
map["left"];
map["right"] = "右边+"; //修改
gy::unordered_map<string, string>::iterator it2 = map.begin();
while (it2 != map.end())
{
cout << it2->first << " " << it2->second << endl;
++it2;
}
cout << endl;
}

key不可取模问题
- 有一些key(日期类等)是不能直接取模的,如果我们在上层传入的K是一个Data类型,那么无法直接进行取模操作,因此我们需要修改代码,因为只有在上层实现传入仿函数,这样我们才能自己控制仿函数的实现
- 修改底层代码
cpp
template<class K, class T,class KeyOfT, class Hash>
class HashTable
{
};
- 修改上层代码
cpp
namespace gy
{
template<class K, class Hash = HashFunc<K>>
class unordered_set
{
private:
hash_bucket::HashTable<K, const K, SetKeyOfT, Hash> _ht;
};
}
namespace gy
{
template<class K, class V, class Hash = HashFunc<K>>
class unordered_map
{
public:
/*typedef typename hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT, Hash> ::Iterator iterator;
typedef typename hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT, Hash> ::Const_Iterator const_iterator;*/
using iterator = typename hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT, Hash> ::Iterator;
using const_iterator = typename hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT, Hash> ::Const_Iterator;
private:
hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT, HashFunc<K>> _ht;
};
}
Erase
- Erase我们只需要将上一节哈希桶的代码小修改即可使用,由于_data类型不确定,因此使用KeyOfT 将key提取出来
cpp
bool Erase(const K& key)
{
Hash hs;
KeyOfT kot;
size_t hashi = hs(key) % _tables.size();
Node* cur = _tables[hashi];
Node* prev = nullptr;
while (cur)
{
if (kot(cur->_data) == key)
{
if (prev == nullptr)
{
_tables[hashi] = cur->_next;
}
else
{
prev->_next = cur->_next;
}
--_n;
delete cur;
return true;
}
prev = cur;
cur = prev->_next;
}
return false;
}
- 上层直接调用底层Erase即可



