unordered_map
无序映射表(Unordered Map)容器是一个存储以键值对组合而成的元素的关联容器(Associative container),容器中的元素无特别的次序关系。该容器允许基于主键地快速检索各个元素
// <unordered_map>
template < class Key,
class T,
class Hash = hash<Key>,
class Pred = equal_to<Key>,
class Alloc = allocator< pair<const Key,T> >
> class unordered_map;
模板参数:
- Key:主键的类型
- T:被映射的值的类型
- Hash:一元谓词,以一个 Key 类型的对象为参数,返回一个基于该对象的 size_t 类型的唯一值
- Pred:二元谓词,以两个 Key 类型的对象为参数,返回一个 bool 值,如果第一个参数等价于第二个参数,该 bool 值为 true,否则为 false
- Alloc:容器内部用来管理内存分配及释放的内存分配器的类型
在一个 unordered_map 容器中,主键通常被用来唯一标志(Uniquely identify)一个元素,而被映射的值保存了与该主键关联的内容。主键与被映射值的类型可以不同,在模板内部,这两种类型合并绑定成成员类型 value_type。由上述描述可知,value_type 是一个双元组类型(Pair type),具体定义如下:
typedef pair<const Key, T> value_type;
在 unordered_map 内部,元素不会按任何顺序排序,而是通过主键的 hash 值将元素分组放置到各个槽(Bucket,也可译成“桶”)中,这样就能通过主键快速地访问各个对应的元素(平均耗时为一个常量,即时间复杂度为 O(1))
在访问容器中的某个元素时,unordered_map 容器比 map 容器高效,而在迭代容器元素的某个子集时,前者比后者稍微低效了一点
unordered_map 实现了直接访问操作符(operator[]),使得可以通过主键(Key value)直接访问被映射的值(Mapped value)
unordered_map 容器支持正向迭代
unordered_map封装实现
通过上面对unordered_map的介绍,unordered_map容器底层使用哈希表的拉链法实现的,前面我们已经实现过处理哈希冲突的拉链法,下面我们自己封装实现一下unordered_map容器
哈希函数的构造:
template <class K>
struct HashFunc
{
size_t operator()(const K& key)
{
return key;
}
};
template <>
struct HashFunc<string> //特化string类型的仿函数
{
static size_t BKDRHash(const char * str)
{
unsigned int seed = 131;
unsigned int hash = 0;
while (*str)
{
hash = hash * seed + (*str++);
}
return (hash & 0x7FFFFFFF);
}
size_t operator()(const string& key)
{
return BKDRHash(key.c_str());
}
};
HashNode结构定义:
template <class K,class V>
struct HashNode
{
pair<const K, V> _kv;//存一个pair结构
HashNode<K, V>* _next;
HashNode(const pair<K, V>& kv)
:_kv(kv)
,_next(NULL)
{}
};
实现迭代器:
template <class K, class V, class HashFunc = _HashFunc<K>>
class HashTable;
template <class K,class V,class Ref,class Ptr>
struct HashIterator
{
typedef struct HashNode<K, V> Node;
typedef HashIterator<K, V, Ref, Ptr> Self;
Node* _node;
HashTable<K, V,HashFunc<K>>* _hashTable;
HashIterator(Node* node, HashTable<K, V, HashFunc<K>>* ht)
:_node(node)
, _hashTable(ht)
{}
Node* _Next()
{
if (_node->_next)
{
return _node->_next;
}//_node->_next==NULL,则需找到哈希表的下一个位置
size_t index = _hashTable->_HashFunc((_node->_kv).first);
for (size_t i = index + 1; i < _hashTable->_table.size(); ++i)
{
if (_hashTable->_table[i])
return _hashTable->_table[i];
}
return NULL;
}
Node* _Prev()
{
//若_node并非当前链表的头结点,则只需找到其所在链表的前一个位置
//若_node为当前链表的头结点,则需要找到哈希表的前一个非空位置链表的最后一个节点
size_t index = _hashTable->_HashFunc((_node->_kv).first);
if (_hashTable->_table[index]!=_node)
{
Node* prev = _hashTable->_table[index];
Node* cur = prev->_next;
while (cur)
{
if (cur == _node)
return prev;
prev = prev->_next;
cur = cur->_next;
}
}
for (size_t i = index - 1; index > 0; --index)
{
if (_hashTable->_table[i])
{
Node* cur = _hashTable->_table[i];
Node* next = cur->_next;
while (next)
{
cur = cur->_next;
next = cur->_next;
}
return cur;
}
}
return NULL;
}
//前置++,返回值为++之后的值
Self& operator++()
{
_node = _Next();
return *this;
}
//后置++,返回值为++之前的值
Self operator++(int)
{
Node* cur = _node;
_node = _Next;
return cur;
}
Self& operator--()
{
_node = _Prev();
return *this;
}
Self operator--(int)
{
Node* cur = _node;
_node = _Prev();
return cur;
}
Ptr operator->()
{
return &_node->_kv;
}
Ref & operator*()
{
return _node->_kv;
}
bool operator==(const Self& tmp)
{
return (_node == tmp._node);
}
bool operator!=(const Self& tmp)
{
return _node != tmp._node;
}
};
实现HashTable:
template <class K, class V, class HashFunc = _HashFunc<K>>
class HashTable
{
typedef struct HashNode<K, V> Node;
public:
typedef HashIterator<K, V, pair<K, V>&, pair<K, V>*> Iterator;
typedef HashIterator<K, V, const pair<K, V>&, const pair<K, V>*> const_Iterator;
friend struct Iterator;
friend struct const_Iterator;
public:
HashTable()
:_size(0)
{
_table.resize(_GetNextPrime(0));
}
~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] = NULL;
}
}
//插入函数
pair<Iterator, bool> Insert(const pair<K, V>& kv)
{
//检查容量
_CheckCapacity();
//先查找
Node * cur = Find(kv.first)._node;
if (cur)//找到返回失败
{
return make_pair(Iterator(cur, this), false);//返回该节点的迭代器,,并且插入失败
}
Node * node = new Node(kv);//新建节点
size_t index = _HashFunc(kv.first);
cur = _table[index];
if (cur)
{
node->_next = cur;
}
_table[index] = node;
++_size;
return make_pair(Iterator(node, this), true);//返回新增的节点的迭代器,,,插入成功
}
//查找函数
Iterator Find(const K& key)
{
size_t index = _HashFunc(key);//找到对应的哈希地址
Node* cur = _table[index];
while (cur)
{
if (cur->_kv.first == key)//找到的话
return Iterator(cur, this);//返回该位置的迭代器
cur = cur->_next;
}
return Iterator(NULL, this);//没找到的话,,返回一个为NULL的迭代器
}
bool Erase(const K& key)
{
Node* cur = Find(key)._node;
if (cur)
{
size_t index = _HashFunc(key);
if (_table[index] == cur)
{
delete cur;
_table[index] = NULL;
}
else
{
Node* prev = _table[index];
while (prev->_next != cur)
{
prev = prev->_next;
}//prev->_next==cur;
delete cur;
prev->_next = NULL;
}
--_size;
return true;
}
return false;
}
Iterator Begin()
{
for (size_t i = 0; i< _table.size(); ++i)
{
Node* cur = _table[i];
if (cur)
{
return Iterator(cur, this);
}
}
return Iterator(NULL, this);
}
const_Iterator Begin()const
{
for (size_t i = 0; i< _tables.size(); ++i)
{
Node* cur = _tables[i];
if (cur)
{
return Iterator(cur, this);
}
}
return Iterator(NULL, this);
}
const_Iterator End()const
{
return Iterator(NULL, this);
}
Iterator End()
{
return Iterator(NULL, this);
}
//使用迭代器输出哈希表内的数据
void Print()
{
Iterator it = Begin();
while (it != End())
{
cout << "("<< it->first << " ," << it->second << ")" << endl;
++it;
}
cout << endl;
}
protected:
void _Swap(HashTable<K, V,HashFunc>& tmp)
{
_table.swap(tmp._table);
swap(_size, tmp._size);
}
void _CheckCapacity()
{
//若哈希表的负载因子>=0.7(也可以是>=1)或者哈希表的长度为0,则进行重构哈希表
if (_size * 10 / _table.size() >= 7 || _table.size() == 0)
{
size_t newSize = _GetNextPrime(_table.size());
//哈希表扩容后进行重构
HashTable<K, V, HashFunc> newTable;
newTable._table.resize(newSize);
//将原哈希表中的元素插入到扩容后的哈希表中
for (size_t i = 0; i < _table.size(); ++i)
{
Node* cur = _table[i];
while (cur)
{
newTable.Insert(cur->_kv);
cur = cur->_next;
}
}
_Swap(newTable);
}
}
size_t _GetNextPrime(const size_t size)
{
const int _PrimeSize = 28;//编译器为我们提供的素数表的长度
//素数表
static const unsigned long _PrimeList[_PrimeSize] =
{
53ul, 97ul, 193ul, 389ul, 769ul,
1543ul, 3079ul, 6151ul, 12289ul, 24593ul,
49157ul, 98317ul, 196613ul, 393241ul, 786433ul,
1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul,
50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul,
1610612741ul, 3221225473ul, 4294967291ul
};
for (size_t i = 0; i < _PrimeSize; ++i)
{
if (_PrimeList[i] > size)//找到下一个素数
{
return _PrimeList[i];
}
}
return _PrimeList[_PrimeSize - 1];//如果要是已经是最大了,,就直接返回最后的值
}
size_t _HashFunc(const K& key)
{
return HashFunc()(key) % _table.size();
}
private:
vector<Node*> _table;
size_t _size;
};
实现UnorderedMap:
template<class K, class V, class HashFunc = _HashFunc<K>>
class UnorderedMap
{
typedef HashTable<K, V, HashFunc> HashTable;
public:
typedef typename HashTable::Iterator Iterator;
typedef typename HashTable::const_Iterator const_Iterator;
UnorderedMap()
{}
//插入函数
pair<Iterator, bool> Insert(const pair<K, V> & kv)
{
return _hashTable.Insert(kv);//直接调用 hash表的函数
}
bool Erase(const K& key)
{
return _hashTable.Erase(key);//调用 删除函数
}
Iterator Find(const K& key)
{
return _hashTable.Find(key);//调用 查找函数
}
Iterator Begin()
{
return _hashTable.Begin();//直接调用
}
const_Iterator Begin()const
{
return _hashTable.Begin();
}
Iterator End()
{
return _hashTable.End();
}
const_Iterator End()const
{
return _hashTable.End();
}
void Print()
{
_hashTable.Print();
}
protected:
HashTable _hashTable;
};