unordered_map&&unordered_set
底层实现
在STL中,C++11引入了unordered_map、unordered_set、unordered_multimap、unordered_multimap。尽管不是名字不是哈希表,但是底层仍然是。相比于map等,这个查找的平均时间更加快。看看它的底层实现(l来自《STL源码剖析》):
//以下是基于gnu2.9版本的提取的
template<class Value, class Key, class HashFcn,
class ExtractKey, class EqualKey,
class Alloc=alloc>
class hashtable{
public:
typedef HashFcn hasher;
typedef EqualKey Key_equal;
typedef size_t size_type;
private:
hasher hash;//哈希函数(可以是函数指针或函数对象(仿函数),返回值需要是bool值)
key_equal equals;//key的判断相等函数(可以是函数指针或函数对象(仿函数)返回值需要是bool值)
ExtractKey get_key;//key的提取函数,从value_type中提取出key
typedef _hashtable_node<Value> node;
vector<node*,Alloc> buckets;//存储桶,可见后面的图示
size_type num_elements;//存储桶的数量
public:
size_type bucket_count() const { return buckets.size()}
……
};
template<class Value>
struct _hashtable_node{
_hashtable_node* next;
Value val;
};
//hashtable的迭代器设计
template<class Value, class Key, class HashFcn,
class ExtractKey, class EqualKey,
class Alloc>
struct _hashtable_iterator{
……
node* cur;
hashtable* ht;
};
//GNU 7.2.0 中重新分解了各种容器的实现细节。此处贴出unordered_map的模板参数部分,也就是我们经常使用的。
template < class Key, // unordered_map::key_type
class T, // unordered_map::mapped_type
class Hash = hash<Key>, // unordered_map::hasher
class Pred = equal_to<Key>, // unordered_map::key_equal
class Alloc = allocator< pair<const Key,T> > // unordered_map::allocator_type
> class unordered_map;
//7.2.0版本已经有默认的hash函数(根据key类型选择的hash函数),只需要定义key与value类型即可。
内存结构:类似deque的分段存储。采用链地址法解决冲突。
构造、析构、赋值
构造
h | 函数原型(C++14) |
---|---|
empty(1) | unordered_map(); //这里的n是什么意思?指定的是数据桶的数量 explicit unordered_map ( size_type n, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& alloc = allocator_type() ); explicit unordered_map ( const allocator_type& alloc ); unordered_map ( size_type n, const allocator_type& alloc ); unordered_map ( size_type n, const hasher& hf, const allocator_type& alloc ); |
range (2) | template< class InputIterator> unordered_map ( InputIterator first, InputIterator last, size_type n = /* see below */, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& alloc = allocator_type() ); template< class InputIterator> unordered_map ( InputIterator first, InputIterator last, size_type n, const allocator_type& alloc ); template< class InputIterator> unordered_map ( InputIterator first, InputIterator last, size_type n, const hasher& hf, const allocator_type& alloc ); |
copy (3) | unordered_map ( const unordered_map& ump ); unordered_map ( const unordered_map& ump, const allocator_type& alloc ); |
move (4) | unordered_map ( unordered_map&& ump ); unordered_map ( unordered_map&& ump, const allocator_type& alloc ); |
initializerlist(5) | unordered_map ( initializer_list il, size_type n = /* see below */, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& alloc = allocator_type() ); unordered_map ( initializer_list il, size_type n, const allocator_type& alloc ); unordered_map ( initializer_list il, size_type n, const hasher& hf, const allocator_type& alloc ); |
上述的size_type n;均是指定指数据桶的数量。初始化一个哈希表的时候注意以下数据桶的数量,数据多,而数据桶少,就会使得查找效率更低。
析构
~unordered_map();
赋值
函数类型 | 函数原型 |
---|---|
copy (1) | unordered_map& operator= ( const unordered_map& ump ); |
move (2) | unordered_map& operator= ( unordered_map&& ump ); |
initializer list (3) | unordered_map& operator= ( intitializer_list il ); |
迭代器与容器大小
Iterators | 函数说明及其函数原型 |
---|---|
begin cbegin |
returns an iterator to the beginning (public member function) iterator begin(); (since C++11) const_iterator begin() const; (since C++11) const_iterator cbegin() const; (since C++11) |
end cend |
returns an iterator to the end (public member function) iterator end(); (since C++11) const_iterator end() const; (since C++11) const_iterator cend() const; (since C++11) |
通过迭代器访问的是值类型。注意unordered_map的值类型是pair<Key,Value>。而unordered_set的值类型就是Key。另外,unordered_map是forward_iterator_tag。单链表类似的访问方式。
Capacity | 函数说明及其函数原型 |
---|---|
empty | checks whether the container is empty (public member function) bool empty() const; (since C++11) |
size | returns the number of elements (public member function) size_type size() const; (since C++11) |
max_size | returns the maximum possible number of elements (public member function) size_type max_size() const; (since C++11) |
修改
各个操作无论是传入参数,还是返回值与map类似。
Modifiers | 函数说明及其函数原型 |
---|---|
clear | clears the contents (public member function) void clear(); (since C++11) |
insert | inserts elements or nodes (since C++17) (public member function) 1-2返回的是,插入成功,返回插入元素的迭代器,以及true。若已有key,插入失败,返回的是已有元素的迭代器,以及false。 (1) pair<iterator,bool> insert ( const value_type& val ); (2) template < class P> pair<iterator,bool> insert ( P&& val ); 3-4返回的是,插入成功,返回插入元素的迭代器。若已有key,插入失败,返回的是已有元素的迭代器。 (3) iterator insert ( const_iterator hint, const value_type& val ); (4) template < class P> iterator insert ( const_iterator hint, P&& val ); (5) template < class InputIterator> void insert ( InputIterator first, InputIterator last ); (6) void insert ( initializer_list<value_type> il |
insert_or_assign(C++17) | inserts an element or assigns to the current element if the key already exists (public member function),插入后会改变value值(即使有相同key元素) |
emplace | constructs element in-place (public member function)即便有相同key的元素,也会构造新元素。 template <class… Args> pair<iterator, bool> emplace ( Args&&… args ); |
emplace_hint | constructs elements in-place using a hint (public member function),在指引迭代器附近插入。可以提高插入效率。 template <class… Args> iterator emplace_hint ( const_iterator position, Args&&… args ); |
try_emplace (C++17) | inserts in-place if the key does not exist, does nothing if the key exists (public member function)如果有相同key元素,不做任何事。 template <class… Args> pair<iterator, bool> try_emplace(const key_type& k, Args&&… args); (1) (since C++17) template <class… Args> pair<iterator, bool> try_emplace(key_type&& k, Args&&… args); (2) (since C++17) template <class… Args> iterator try_emplace(const_iterator hint, const key_type& k, Args&&… args); (3) (since C++17) template <class… Args> iterator try_emplace(const_iterator hint, key_type&& k, Args&&… args); (4) (since C++17) |
erase | erases elements (public member function)三种方式删除元素 by position (1) iterator erase ( const_iterator position ); by key (2) size_type erase ( const key_type& k ); range (3) iterator erase ( const_iterator first, const_iterator last ); |
swap | swaps the contents (public member function),交换指针一些东西,效率挺高 void swap ( unordered_map& ump ); |
extract (C++17) | extracts nodes from the container (public member function) node_type extract( const_iterator position ); (1) (since C++17) node_type extract( const key_type& x ); (2) (since C++17) |
merge (C++17) | splices nodes from another container (public member function) template<class H2, class P2> void merge(std::unordered_map<Key, T, H2, P2, Allocator>& source); template<class H2, class P2> void merge(std::unordered_map<Key, T, H2, P2, Allocator>&& source); |
notes:
对于unorder_map,每个数据桶只能装一个元素。
对于extract:(唯一一种改变元素key值而不需要重新申请内存分配的,要使用move)
extract is the only way to change a key of a map element without reallocation。
merge:从source中提取不同key的元素(是对于* this的hash函数以及key相等函数的意义上的key不同)。* this与source要求分配器类型是一致的。
另外,无论是insert,emplace等,他们如果增加了元素。会在当前size()>最大装载因子*数据桶数量的时候进行rehash。rehash的意思是:增大数据桶的数量。装载因子等于
查询
在unordered_multimap中无at,operator[ ]。
Lookup | |
---|---|
at | access specified element with bounds checking (public member function)注意返回的是mapped_type。 mapped_type& at ( const key_type& k ); const mapped_type& at ( const key_type& k ) const; |
operator[ ] | access specified element (public member function) mapped_type& operator[] ( const key_type& k ); mapped_type& operator[] ( key_type&& k ); |
count | returns the number of elements matching specific key (public member function),返回特定key的元素数量 size_type count ( const key_type& k ) const; |
find | finds element with specific key (public member function),两种寻找方式,通过迭代器或通过key寻找元素 iterator find( const Key& key ); (1) const_iterator find( const Key& key ) const; (2) |
equal_range | returns range of elements matching a specific key (public member function)左闭右开区间,包含所有特定的key。 std::pair<iterator,iterator> equal_range( const Key& key ); (since C++11) std::pair<const_iterator,const_iterator> equal_range( const Key& key ) const; (since C++11) |
数据桶信息
数据通接口 | 函数原型及其说明 |
---|---|
begin(int) cbegin(int) |
returns an iterator to the beginning of the specified bucket (public member function)返回指定数据桶的第一个元素的迭代器 local_iterator begin( size_type n ); (since C++11) const_local_iterator begin( size_type n ) const; (since C++11) const_local_iterator cbegin( size_type n ) const; |
end(int) cend(int) |
returns an iterator to the end of the specified bucket (public member function) local_iterator end( size_type n ); (since C++11) const_local_iterator end( size_type n ) const; (since C++11) const_local_iterator cend( size_type n ) const; (since C++11) |
bucket_count | returns the number of buckets,返回桶的数量 (public member function) size_type bucket_count() const; (since C++11) |
max_bucket_count | returns the maximum number of buckets ,返回桶的最大数量(public member function) size_type max_bucket_count() const; (since C++11) |
bucket_size | returns the number of elements in specific bucket,返回特定桶中的元素数量 (public member function) size_type bucket_size( size_type n ) const; (since C++11) |
bucket | returns the bucket for specific key, 返回key对应的桶编号(public member function) size_type bucket( const Key& key ) const; (since C++11) |
哈希策略
Hash policy | |
---|---|
load_factor | returns average number of elements per bucket (public member function),装载因子就是元素个数除以数据桶个数 float load_factor() const; (since C++11) |
max_load_factor | manages maximum average number of elements per bucket (public member function),如果超过这个装载因子就会重新设置桶的数量。默认最大装载因子为1,可以自己设置。 float max_load_factor() const; (1) (since C++11) void max_load_factor( float ml ); (2) (since C++11) |
rehash | reserves at least the specified number of buckets. This regenerates the hash table. (public member function),如果设置的桶数量,超过最大装载因子不会重新hash。 void rehash( size_type count ); (since C++11) |
reserve | reserves space for at least the specified number of elements. This regenerates the hash table.由元素数量申请空间(就是hash表的空间) (public member function) void reserve( size_type count ); (since C++11) |
一些仿函数
Observers | |
---|---|
hash_function | returns function used to hash the keys (public member function) hasher hash_function() const; (since C++11) |
key_eq | returns the function used to compare keys for equality (public member function) key_equal key_eq() const; (since C++11) |
与unordered_set等的关系
就像map与set一样,unordered_map与unordered_set之间最要注意的区别就是值类型不一致,一个是pair<key,map_type>,另外一个key类型就是值类型。而unordered_map与unordered_multimap,unordered_map要求相同的key的元素只有一个,而unordered_multimap,就可以有多个相同的key元素。
Reference
[1] https://www.bilibili.com/video/av45108908
[2]http://www.cplusplus.com/reference/unordered_map/
[3]候捷,《STL源码剖析》
原文链接: https://www.cnblogs.com/maricat4/p/14710707.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;
也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/330706
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!