在C++98中,STL提供了底层为红黑树结构的一系列关联式容器,例如map、set等。它们在搜索数据时效率可达到O(logN),但最糟糕的情况下搜索需要比较红黑树的高度次,若此时树中的节点非常之多,那么搜索效率就非常不理想。
最理想的搜索是,进行较少的比较次数就能够将元素找到。于是,在C++11中,STL又提供了4个unordered系列的关联式容器,即unordered_map 、unordered_set、unordered_multimap和unordered_multiset。这四个容器与红黑树结构的关联式容器的使用方式基本类似,但不同的是,它们的底层结构为哈希桶。
本篇博客unordered_map和unordered_set的特性和常见用法,并搭配对STL源码的模拟实现,旨在更好地帮助读者理解容器的功能。
目录
一、无序的关联式容器
1.Unordered_map
Unordered_map(无序映像)是一种存储<key,value>键值对的关联式容器,使用时需包含该容器的头文件“#include<unordered_map>”,底层为哈希桶,支持通过key快速地索引到与之对应的value(为了能在常数范围内找到key所对应的value,它将具有相同哈希地址的键值对放在相同的桶中)。
对于unordered_map中的元素,键值key通常用于惟一地标识它,实值value则表示它本身的值。键值key和实值value是一一对应的,它们的类型可以不同。它们在容器内没有对按照任何特定的顺序来排序,所以unordered_map相当于是map的”不排序但去重“版本。
Unordered_map通过key访问单个元素要比map快(这是因为其底层是哈希桶),但在遍历迭代方面效率通常较低。它支持下标访问符[ ],允许使用key作为参数直接访问value。
Unordered_map的迭代器一般为正向迭代器。
#include<unordered_map>
void test_unordered_map()
{
unordered_map<string, string> up; //调用默认构造定义一个空的容器
unordered_map<string, string> up2(up);//调用拷贝构造创建并初始化一个容器
//emplace()构造并插入元素
up.emplace("1", "apple");
up.emplace("2", "banana");
up.emplace("3", "orange");
up.emplace("4", "pear");
up.emplace("5", "watermelon");
//迭代器遍历
for ( auto it = up.begin(); it != up.end(); ++it )
{
cout << " " << it->first << ":" << it->second << endl;
}
//insert()插入元素
up2.insert ( {{"sugar",0.8},{"salt",0.1}} ); //默认构造插入
pair<string,double> myshopping ("baking powder",0.3);
up2.insert (myshopping); //拷贝构造插入
up2.insert (make_pair<string,double>("eggs",6.0)); //移动构造插入
up2.insert (up.begin(), up.end()); //迭代器范围插入
//范围for遍历容器
for (auto& kv : up2)
{
cout << kv.first << ":" << kv.second << endl;
}
//通过[]也可以插入元素
unordered_map<string, string> dict;
dict["sort"] = "排序";
dict["insert"] = "插入";
dict["string"] = "字符串";
dict["left"];
for (auto& kv : dict)
{
cout << kv.first << ":" << kv.second << endl;
}
//查找
auto it = dict.find(sort);
if ( it == dict.end() )
{
cout << "not found" << endl;
}
else
{
cout << it->first << " is " << it->second << endl;
}
string s="insert";
if (dict.count(s)>0)
{
cout << "dict has " << s << endl;
}
//删除
up.erase ( up.begin() ); //迭代器指定删除
up.erase ("2"); //key指定删除
up.erase ( up.find("3"), up.end() ); //迭代器范围删除
//验空+查大小
if( up.empty() )
{
cout << up.size() << endl;
}
}
2.Unordered_set
Unordered_set(无序集合)是一种只存储键值key的关联式容器,使用时需包含该容器的头文件“#include<unordered_set>”,底层为哈希桶,支持对键值key的快速检索。
对于unordered_set中的元素,它们的实值同时也是唯一标识它的键值。键值key在设置上是不可变的,因此,容器中的元素不可修改,只可插入和删除。容器中的元素没有对按照任何特定的顺序来排序,所以unordered_set相当于是set的”不排序但去重“版本。
Unordered_set访问单个元素要比set快(这是因为其底层是哈希桶),但在遍历迭代方面效率通常较低。
Unordered_set的迭代器一般为正向迭代器。
void test_unordered_set()
{
//unordered_set仅能去重
unordered_set<int> us; //调用默认构造定义一个空的容器
unordered_set<int> us2(us);//调用拷贝构造创建并初始化一个容器
//插入
us.insert(3);
us.insert(1);
us.insert(3);
us.insert(4);
us.insert(5);
//迭代器遍历
unordered_set<int>::iterator it = us.begin();
while (it != us.end())
{
cout << *it << "";//3 1 4 5
++it;
}
cout << endl;
//查找
for (auto& x: us)
{
if (myset.count(x)>0) cout << "us has " << x << endl;
else cout << "us has no " << x << endl;
}
unordered_set<int>::const_iterator got = us.find (6);
if ( got == myset.end() ) cout << "not found in us";
else cout << *got << " is in us";
//删除
us.erase ( us.begin() );
us.erase (4);
us.erase (us.find(1), us.end() );
}
二、同一种底层数据结构支持两种不同的容器
(这一小节在【C++】map 和 set 中有逻辑相似的、更加详细的STL源码解析)
1.底层哈希桶的实现
(关于哈希桶的更多解析详见:【数据结构】哈希)
//HashTable.h
#include<vector>
template<class K>
struct DefaultHashFunc
{
size_t operator()(const K& key)
{
return (size_t)key;
}
};
template<>
struct DefaultHashFunc<string>
{
size_t operator()(const string& str)
{
size_t hash = 0;
for (auto ch : str)
{
hash *= 131;
hash += ch;
}
return hash;
}
};
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 KeyOfT, class HashFunc = DefaultHashFunc<K>>
class HashTable
{
typedef HashNode<T> Node;
public:
HashTable()
{
_table.resize(10, nullptr);
}
~HashTable()
{
for (size_t i = 0; i < _table.size(); i++)
{
Node* cur = _table[i];
while (cur)
{
Node* next = cur->_next;
delete cur;
cur = next;
}
_table[i] = nullptr;
}
}
bool Insert(const T& data)
{
KeyOfT kot;
if(Find(kot(data)))
{
return false;
}
HashFunc hf;
if (_n == _table.size())
{
size_t newSize = _table.size()*2;
vector<Node*> newTable;
newTable.resize(newSize, nullptr);
for (size_t i = 0; i < _table.size(); i++)
{
Node* cur = _table[i];
while (cur)
{
Node* next = cur->_next;
size_t hashi = hf(kot(cur->_data)) % newSize;
cur->_next = newTable[hashi];
newTable[hashi] = cur;
cur = next;
}
_table[i] = nullptr;
}
_table.swap(newTable);
}
size_t hashi = hf(kot(data)) % _table.size();
Node* newnode = new Node(data);
newnode->_next = _table[hashi];
_table[hashi] = newnode;
++_n;
return true;
}
Node* Find(const K& key)
{
HashFunc hf;
KeyOfT kot;
size_t hashi = hf(key) % _table.size();
Node* cur = _table[hashi];
while (cur)
{
if (kot(cur->_data) == key)
{
return cur;
}
cur = cur->_next;
}
return nullptr;
}
bool Erase(const K& key)
{
HashFunc hf;
KeyOfT kot;
size_t hashi = hf(key) % _table.size();
Node* prev = nullptr;
Node* cur = _table[hashi];
while (cur)
{
if (kot(cur->_data) == key)
{
if (prev == nullptr)
{
_table[hashi] = cur->_next;
}
else
{
prev->_next = cur->_next;
}
--_n;
delete cur;
return true;
}
prev = cur;
cur = cur->_next;
}
return false;
}
private:
vector<Node*> _table; // 挂满链表的指针数组
size_t _n = 0; // 有效数据个数
};
}
2.上层的初步封装
· unordered_map
//unordered_map.h
#include"HashTable.h"
namespace CVE
{
template<class K, class V>
class unordered_map
{
struct MapKeyOfT
{
const K& operator()(const pair<K, V>& kv)
{
return kv.first;
}
};
private:
hash_bucket::HashTable<K, pair<K, V>, MapKeyOfT> _ht;
};
}
// unordered_map -> hash_bucket::HashTable<K, pair<K, V>> _ht;
// unordered_set -> hash_bucket::HashTable<K, K> _ht;
· unordered_set
//unordered_set.h
#include"HashTable.h"
namespace CVE
{
template<class K>
class unordered_set
{
struct SetKeyOfT
{
const K& operator()(const K& key)
{
return key;
}
};
private:
hash_bucket::HashTable<K, K, SetKeyOfT> _ht;
};
}
// unordered_map -> hash_bucket::HashTable<K, pair<K, V>> _ht;
// unordered_set -> hash_bucket::HashTable<K, K> _ht;
3.普通迭代器
· 基本结构
//HashTable.h
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 KeyOfT, class HashFunc>
class HashTable;
//普通迭代器
template<class K, class T, class KeyOfT, class HashFunc>
struct HTIterator
{
typedef HashNode<T> Node;
typedef HTIterator<K, T, KeyOfT, HashFunc> Self;
Node* _node; //哈希桶的当前节点
HashTable<K, T, KeyOfT, HashFunc>* _pht; //哈希桶的指针
//构造函数
HTIterator(Node* node, HashTable<K, T, KeyOfT, HashFunc>* pht)
:_node(node)
,_pht(pht)
{}
//...
//哈希桶(哈希表)
template<class K, class T, class KeyOfT, class HashFunc = DefaultHashFunc<K>>
class HashTable
{
//...
public:
typedef HTIterator<K, T, KeyOfT, HashFunc> iterator;
//...
};
}
· 相关功能
//HashTable.h
namespace hash_bucket
{
//...
template<class K, class T, class KeyOfT, class HashFunc>
struct HTIterator
{
typedef HashNode<T> Node;
typedef HTIterator<K, T, KeyOfT, HashFunc> Self;
Node* _node; //哈希桶的当前节点
HashTable<K, T, KeyOfT, HashFunc>* _pht; //哈希桶的指针
HTIterator(Node* node, HashTable<K, T, KeyOfT, HashFunc>* pht)
:_node(node)
,_pht(pht)
{}
//*重载
T& operator*()
{
return _node->_data;
}
//->重载
T* operator->()
{
return &_node->_data;
}
//++重载
Self& operator++()
{
//_node是某一个桶中的当前节点的指针
// 当前桶中链表还没完,就遍历到下一个链表节点
if (_node->_next)
{
_node = _node->_next;
}
// 当前桶中链表走完了,就去找下一个挂了链表的桶(即不为空的桶)
else
{
// 取当前桶的哈希地址
KeyOfT kot;
HashFunc hf;
size_t hashi = hf(kot(_node->_data)) % _pht->_table.size();
// 去下一个相邻的哈希地址查找下一个不为空的桶
++hashi;
while (hashi < _pht->_table.size())
{
//找到了,将_node(当前节点的指针)置为找到的桶的指针,并返回
if (_pht->_table[hashi])
{
_node = _pht->_table[hashi];
return *this;
}
//没找到就再去下一个相邻的哈希地址找
else
{
++hashi;
}
}
_node = nullptr;
}
//遍历到桶中的下一个节点,或哈希表遍历完了,都返回当前节点(的指针)
return *this;
}
//!=重载
bool operator!=(const Self& s)
{
return _node != s._node;
}
};
template<class K, class T, class KeyOfT, class HashFunc = DefaultHashFunc<K>>
class HashTable
{
typedef HashNode<T> Node;
// 友元声明
// 否则HTIterator的对象无法访问HashTable的私有成员
template<class K, class T, class KeyOfT, class HashFunc>
friend struct HTIterator;
public:
typedef HTIterator<K, T, KeyOfT, HashFunc> iterator;
iterator begin()
{
// 找第一个桶
for (size_t i = 0; i < _table.size(); i++)
{
Node* cur = _table[i];
if (cur)
{
return iterator(cur, this);
}
}
return iterator(nullptr, this);
}
iterator end()
{
return iterator(nullptr, this);
}
//...
}
}
· 上层的进一步封装
· unordered_map
//unordered_map.h
#include"HashTable.h"
namespace CVE
{
template<class K, class V>
class unordered_map
{
struct MapKeyOfT
{
const K& operator()(const pair<K, V>& kv)
{
return kv.first;
}
};
public:
typedef typename hash_bucket::HashTable<K, pair<K, V>, MapKeyOfT>::iterator iterator;
iterator begin()
{
return _ht.begin();
}
iterator end()
{
return _ht.end();
}
private:
hash_bucket::HashTable<K, pair<K, V>, MapKeyOfT> _ht;
};
}
· unordered_set
//unordered_set.h
#include"HashTable.h"
namespace CVE
{
template<class K>
class unordered_set
{
struct SetKeyOfT
{
const K& operator()(const K& key)
{
return key;
}
};
public:
typedef typename hash_bucket::HashTable<K, K, SetKeyOfT>::iterator iterator;
iterator begin()
{
return _ht.begin();
}
iterator end()
{
return _ht.end();
}
private:
hash_bucket::HashTable<K, K, SetKeyOfT> _ht;
};
}
4.const迭代器
· 基本结构
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 KeyOfT, class HashFunc>
class HashTable;
template<class K, class T, class Ptr, class Ref, class KeyOfT, class HashFunc>
struct HTIterator
{
typedef HashNode<T> Node;
typedef HTIterator<K, T, Ptr, Ref, KeyOfT, HashFunc> Self;
typedef HTIterator<K, T, T*, T&, KeyOfT, HashFunc> Iterator;
Node* _node;
const HashTable<K, T, KeyOfT, HashFunc>* _pht;
HTIterator(Node* node, const HashTable<K, T, KeyOfT, HashFunc>* pht)
:_node(node)
, _pht(pht)
{}
// 对于普通迭代器对象,这是拷贝构造
// 对于const迭代器对象,这是构造,同时也支持普通迭代器去构造const迭代器
HTIterator(const Iterator& it)
:_node(it._node)
, _pht(it._pht)
{}
Ref operator*()
{
return _node->_data;
}
Ptr operator->()
{
return &_node->_data;
}
Self& operator++()
{
if (_node->_next)
{
_node = _node->_next;
}
else
{
KeyOfT kot;
HashFunc hf;
size_t hashi = hf(kot(_node->_data)) % _pht->_table.size();
++hashi;
while (hashi < _pht->_table.size())
{
if (_pht->_table[hashi])
{
_node = _pht->_table[hashi];
return *this;
}
else
{
++hashi;
}
}
_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 HashFunc = DefaultHashFunc<K>>
class HashTable
{
typedef HashNode<T> Node;
// 友元声明
template<class K, class T, class Ptr, class Ref, class KeyOfT, class HashFunc>
friend struct HTIterator;
public:
typedef HTIterator<K, T, T*, T&, KeyOfT, HashFunc> iterator;
typedef HTIterator<K, T, const T*, const T&, KeyOfT, HashFunc> const_iterator;
iterator begin()
{
for (size_t i = 0; i < _table.size(); i++)
{
Node* cur = _table[i];
if (cur)
{
return iterator(cur, this);
}
}
return iterator(nullptr, this);
}
iterator end()
{
return iterator(nullptr, this);
}
const_iterator begin() const
{
for (size_t i = 0; i < _table.size(); i++)
{
Node* cur = _table[i];
if (cur)
{
return const_iterator(cur, this);
}
}
return const_iterator(nullptr, this);
}
const_iterator end() const
{
return const_iterator(nullptr, this);
}
//...
private:
vector<Node*> _table;
size_t _n = 0;
};
}
· 上层的进一步封装
· unordered_map
#include"HashTable.h"
namespace CVE
{
template<class K, class V>
class unordered_map
{
struct MapKeyOfT
{
const K& operator()(const pair<const K, V>& kv)
{
return kv.first;
}
};
public:
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();
}
//...
private:
hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT> _ht;
};
}
· unordered_set
#pragma once
#include"HashTable.h"
namespace CVE
{
template<class K>
class unordered_set
{
struct SetKeyOfT
{
const K& operator()(const K& key)
{
return key;
}
};
public:
typedef typename hash_bucket::HashTable<K, K, SetKeyOfT>::const_iterator iterator;
typedef typename hash_bucket::HashTable<K, K, SetKeyOfT>::const_iterator const_iterator;
const_iterator begin() const
{
return _ht.begin();
}
const_iterator end() const
{
return _ht.end();
}
//...
private:
hash_bucket::HashTable<K, K, SetKeyOfT> _ht;
};
}
5.insert() 的返回值与operator[ ]
//HashTable.h
namespace hash_bucket
{
//...
template<class K, class T, class KeyOfT, class HashFunc = DefaultHashFunc<K>>
class HashTable
{
typedef HashNode<T> Node;
template<class K, class T, class Ptr, class Ref, class KeyOfT, class HashFunc>
friend struct HTIterator;
public:
typedef HTIterator<K, T, T*, T&, KeyOfT, HashFunc> iterator;
typedef HTIterator<K, T, const T*, const T&, KeyOfT, HashFunc> const_iterator;
//...
pair<iterator, bool> Insert(const T& data)
{
KeyOfT kot;
iterator it = Find(kot(data));
if(it != end())
{
return make_pair(it, false);
}
HashFunc hf;
if (_n == _table.size())
{
//size_t newSize = _table.size() * 2;
size_t newSize = GetNextPrime(_table.size());
vector<Node*> newTable;
newTable.resize(newSize, nullptr);
for (size_t i = 0; i < _table.size(); i++)
{
Node* cur = _table[i];
while (cur)
{
Node* next = cur->_next;
size_t hashi = hf(kot(cur->_data)) % newSize;
cur->_next = newTable[hashi];
newTable[hashi] = cur;
cur = next;
}
_table[i] = nullptr;
}
_table.swap(newTable);
}
size_t hashi = hf(kot(data)) % _table.size();
Node* newnode = new Node(data);
newnode->_next = _table[hashi];
_table[hashi] = newnode;
++_n;
return make_pair(iterator(newnode, this), true);
}
iterator Find(const K& key)
{
HashFunc hf;
KeyOfT kot;
size_t hashi = hf(key) % _table.size();
Node* cur = _table[hashi];
while (cur)
{
if (kot(cur->_data) == key)
{
return iterator(cur, this);
}
cur = cur->_next;
}
return end();
}
//...
private:
vector<Node*> _table;
size_t _n = 0;
};
}
//unordered_map.h
#include"HashTable.h"
namespace CVE
{
template<class K, class V>
class unordered_map
{
struct MapKeyOfT
{
const K& operator()(const pair<const K, V>& kv)
{
return kv.first;
}
};
public:
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();
}
pair<iterator, bool> insert(const pair<K, V>& kv)
{
return _ht.Insert(kv);
}
V& operator[](const K& key)
{
pair<iterator, bool> ret = _ht.Insert(make_pair(key, V()));
return ret.first->second;
}
private:
hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT> _ht;
};
}
6.键值不匹配的解决方案
//unordered_set.h
#include"HashTable.h"
namespace CVE
{
template<class K>
class unordered_set
{
struct SetKeyOfT
{
const K& operator()(const K& key)
{
return key;
}
};
public:
typedef typename hash_bucket::HashTable<K, K, SetKeyOfT>::const_iterator iterator;
typedef typename hash_bucket::HashTable<K, K, SetKeyOfT>::const_iterator const_iterator;
const_iterator begin() const
{
return _ht.begin();
}
const_iterator end() const
{
return _ht.end();
}
pair<const_iterator, bool> insert(const K& key)
{
pair<typename hash_bucket::HashTable<K, K, SetKeyOfT>::iterator, bool> ret = _ht.Insert(key);
//先用一个<普通迭代器,布尔值>的对象接收插入方法的返回值
return pair<const_iterator, bool>(ret.first, ret.second);
//再将对象中的普通迭代器通过构造函数构造为const迭代器
}
private:
hash_bucket::HashTable<K, K, SetKeyOfT> _ht;
};
}
7.模拟实现的完整代码
· HashTable.h
#include<vector>
template<class K>
struct DefaultHashFunc
{
size_t operator()(const K& key)
{
return (size_t)key;
}
};
template<>
struct DefaultHashFunc<string>
{
size_t operator()(const string& str)
{
size_t hash = 0;
for (auto ch : str)
{
hash *= 131;
hash += ch;
}
return hash;
}
};
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 KeyOfT, class HashFunc>
class HashTable;
template<class K, class T, class Ptr, class Ref, class KeyOfT, class HashFunc>
struct HTIterator
{
typedef HashNode<T> Node;
typedef HTIterator<K, T, Ptr, Ref, KeyOfT, HashFunc> Self;
typedef HTIterator<K, T, T*, T&, KeyOfT, HashFunc> Iterator;
Node* _node;
const HashTable<K, T, KeyOfT, HashFunc>* _pht;
HTIterator(Node* node, const HashTable<K, T, KeyOfT, HashFunc>* pht)
:_node(node)
, _pht(pht)
{}
HTIterator(const Iterator& it)
:_node(it._node)
, _pht(it._pht)
{}
Ref operator*()
{
return _node->_data;
}
Ptr operator->()
{
return &_node->_data;
}
Self& operator++()
{
if (_node->_next)
{
_node = _node->_next;
}
else
{
KeyOfT kot;
HashFunc hf;
size_t hashi = hf(kot(_node->_data)) % _pht->_table.size();
++hashi;
while (hashi < _pht->_table.size())
{
if (_pht->_table[hashi])
{
_node = _pht->_table[hashi];
return *this;
}
else
{
++hashi;
}
}
_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 HashFunc = DefaultHashFunc<K>>
class HashTable
{
typedef HashNode<T> Node;
template<class K, class T, class Ptr, class Ref, class KeyOfT, class HashFunc>
friend struct HTIterator;
public:
typedef HTIterator<K, T, T*, T&, KeyOfT, HashFunc> iterator;
typedef HTIterator<K, T, const T*, const T&, KeyOfT, HashFunc> const_iterator;
iterator begin()
{
for (size_t i = 0; i < _table.size(); i++)
{
Node* cur = _table[i];
if (cur)
{
return iterator(cur, this);
}
}
return iterator(nullptr, this);
}
iterator end()
{
return iterator(nullptr, this);
}
const_iterator begin() const
{
for (size_t i = 0; i < _table.size(); i++)
{
Node* cur = _table[i];
if (cur)
{
return const_iterator(cur, this);
}
}
return const_iterator(nullptr, this);
}
const_iterator end() const
{
return const_iterator(nullptr, this);
}
//每次快速取模的是一个类似两倍关系的素数,可以更好地支持除留余数法寻址和扩容
//但这个方法并没有明确的理论依据
//C++的STL库中用了这样的方法,而Java库中没有用
size_t GetNextPrime(size_t prime)
{
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
};
size_t i = 0;
for (; i < PRIMECOUNT; ++i)
{
if (primeList[i] > prime)
return primeList[i];
}
return primeList[i];
}
HashTable()
{
_table.resize(GetNextPrime(1), nullptr);
}
~HashTable()
{
for (size_t i = 0; i < _table.size(); i++)
{
Node* cur = _table[i];
while (cur)
{
Node* next = cur->_next;
delete cur;
cur = next;
}
_table[i] = nullptr;
}
}
pair<iterator, bool> Insert(const T& data)
{
KeyOfT kot;
iterator it = Find(kot(data));
if(it != end())
{
return make_pair(it, false);
}
HashFunc hf;
if (_n == _table.size())
{
size_t newSize = GetNextPrime(_table.size());
vector<Node*> newTable;
newTable.resize(newSize, nullptr);
for (size_t i = 0; i < _table.size(); i++)
{
Node* cur = _table[i];
while (cur)
{
Node* next = cur->_next;
size_t hashi = hf(kot(cur->_data)) % newSize;
cur->_next = newTable[hashi];
newTable[hashi] = cur;
cur = next;
}
_table[i] = nullptr;
}
_table.swap(newTable);
}
size_t hashi = hf(kot(data)) % _table.size();
Node* newnode = new Node(data);
newnode->_next = _table[hashi];
_table[hashi] = newnode;
++_n;
return make_pair(iterator(newnode, this), true);
}
iterator Find(const K& key)
{
HashFunc hf;
KeyOfT kot;
size_t hashi = hf(key) % _table.size();
Node* cur = _table[hashi];
while (cur)
{
if (kot(cur->_data) == key)
{
return iterator(cur, this);
}
cur = cur->_next;
}
return end();
}
bool Erase(const K& key)
{
HashFunc hf;
KeyOfT kot;
size_t hashi = hf(key) % _table.size();
Node* prev = nullptr;
Node* cur = _table[hashi];
while (cur)
{
if (kot(cur->_data) == key)
{
if (prev == nullptr)
{
_table[hashi] = cur->_next;
}
else
{
prev->_next = cur->_next;
}
--_n;
delete cur;
return true;
}
prev = cur;
cur = cur->_next;
}
return false;
}
private:
vector<Node*> _table;
size_t _n = 0;
};
}
· unordered_map.h
#include"HashTable.h"
namespace CVE
{
template<class K, class V>
class unordered_map
{
struct MapKeyOfT
{
const K& operator()(const pair<const K, V>& kv)
{
return kv.first;
}
};
public:
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();
}
pair<iterator, bool> insert(const pair<K, V>& kv)
{
return _ht.Insert(kv);
}
V& operator[](const K& key)
{
pair<iterator, bool> ret = _ht.Insert(make_pair(key, V()));
return ret.first->second;
}
private:
hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT> _ht;
};
}
· unordered_set.h
#include"HashTable.h"
namespace CVE
{
template<class K>
class unordered_set
{
struct SetKeyOfT
{
const K& operator()(const K& key)
{
return key;
}
};
public:
typedef typename hash_bucket::HashTable<K, K, SetKeyOfT>::const_iterator iterator;
typedef typename hash_bucket::HashTable<K, K, SetKeyOfT>::const_iterator const_iterator;
const_iterator begin() const
{
return _ht.begin();
}
const_iterator end() const
{
return _ht.end();
}
pair<const_iterator, bool> insert(const K& key)
{
pair<typename hash_bucket::HashTable<K, K, SetKeyOfT>::iterator, bool> ret = _ht.Insert(key);
return pair<const_iterator, bool>(ret.first, ret.second);
}
private:
hash_bucket::HashTable<K, K, SetKeyOfT> _ht;
};
}