unordered_map&&unordered_set

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大佬

    unordered_map&&unordered_set

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/330706

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年3月1日 下午5:42
下一篇 2023年3月1日 下午5:42

相关推荐