C++ unordered_map/multimap使用
unordered_map
概述
- unordered_map 与 unordered_multimap 都定义于头文件<unordered_map>
- unordered_map 是关联容器,含有带唯一键的键-值 pair 。搜索、插入和元素移除拥有平均常数时间复杂度。
- unordered_multimap 可以含有不唯一的 Key 。
- unordered_map 与 unordered_multimap 成员函数及非成员函数使用方法相同,只是在 insert 函数内部,unordered_map 调用 insert_unique 函数不允许键重复,而 unordered_multimap 调用 insert_equal 函数允许键重复。
- 在内部,元素并不以任何特别顺序排序,而是组织进桶中。元素被放进哪个桶完全依赖其值的哈希。这允许对单独元素的快速访问,因为哈希一旦确定,就准确指代元素被放入的桶。
类模板:
template<
class Key,
class T,
class Hash = std::hash<Key>,
class KeyEqual = std::equal_to<Key>,
class Allocator = std::allocator< std::pair<const Key, T> >
> class unordered_map;
创建unordered_map
构造函数
// 默认构造函数:空 unordered_map
std::unordered_map<std::string, std::string> m1;
// 列表构造函数
std::unordered_map<int, std::string> m2 =
{
{1, "foo"},
{3, "bar"},
{2, "baz"},
};
// 复制构造函数
std::unordered_map<int, std::string> m3 = m2;
// 移动构造函数
std::unordered_map<int, std::string> m4 = std::move(m2);
// 范围构造函数
std::vector<std::pair<std::bitset<8>, int>> v = { {0x12, 1}, {0x01,-1} };
std::unordered_map<std::bitset<8>, double> m5(v.begin(), v.end());
opertor=
- 赋值给容器
定义:
// 复制赋值运算符。
unordered_map& operator=( const unordered_map& other );
// 移动赋值运算符
unordered_map& operator=( unordered_map&& other );
// 以 initializer_unordered_map iunordered_map 所标识者替换内容
unordered_map& operator=( std::initializer_unordered_map<T> iunordered_map );
用法:
std::unordered_map<int> nums1 {3, 1, 4, 6, 5, 9};
std::unordered_map<int> nums2;
std::unordered_map<int> nums3;
// 从 nums1 复制赋值数据到 nums2
nums2 = nums1;
// 从 nums1 移动赋值数据到 nums3,
nums3 = std::move(nums1);
// initializer_unordered_map 的复制赋值复制数据给 nums1
nums1 = {1, 2, 3};
迭代器
begin\cbegin
- 返回指向 unordered_map 首元素的迭代器。
- cbegin中的c表示const,即返回const_iterator,不允许通过迭代器修改元素。
- 若 unordered_map 为空,则返回的迭代器将等于 end() 。
定义:
iterator begin();
const_iterator cbegin() const noexcept;
end\cend
- 返回指向 unordered_map 末元素后一元素的迭代器。
定义:
iterator end();
const_iterator cend() const noexcept;
容量
empty
- 检查容器是否无元素,即是否 begin() == end() 。
定义:
bool empty() const;
用法:
std::unordered_map<int, int> v;
bool flag = v.empty(); // 输出 true
size
- 返回容纳的元素数。 即 std::distance(begin(), end()) 。
定义:
size_type size() const;
用法:
std::unordered_map<int, int> nums {1, 3, 5, 7};
std::cout << nums.size() << std::endl; // 输出 4
max_size
- 返回根据系统或库实现限制的容器可保有的元素最大数量,即对于最大容器的 std::distance(begin(), end()) 。
定义:
size_type max_size() const;
用法:
std::unordered_map<int, int> vi;
std::cout << vi.max_size() << std::endl; // 可能输出 4611686018427387903
std::unordered_map<char, char> vc;
std::cout << vc.max_size() << std::endl; // 可能输出 18446744073709551615
修改器
clear
- 从容器擦除所有元素。此调用后 size() 返回零。
- 非法化任何指代所含元素的引用、指针或迭代器。任何尾后迭代器亦被非法化。
定义:
void clear();
用法:
std::unordered_map<int, char> container{{1, 'x'}, {2, 'y'}, {3, 'z'}};
container.clear();
std::cout << container.size() << std::endl; // 输出 0
insert
- 插入元素或结点
定义:
std::pair<iterator,bool> insert( const value_type& value );
std::pair<iterator,bool> insert( value_type&& value );
template< class InputIt >
void insert( InputIt first, InputIt last );
void insert( std::initializer_list<value_type> ilist );
用法:
std::unordered_map<int, char> a;
a.insert({4, 'c'});
std::unordered_map<int, char> b {{1, 'x'}, {2, 'y'}, {3, 'z'}};
a.insert(b.begin(), b.end());
a.insert({6, 'x'}, {7, 'y'});
insert_or_assign
- 若等价于 k 的键已存在于容器中,则赋值 std::forward(obj) 给对应于键 k 的 mapped_type 。若键不存在,则如同用 insert 插入从 value_type(k, std::forward(obj)) 构造的新值。
std::unordered_map<int, char> a{ {1, 'a'}, {2, 'b'} };
a.insert({ 3, 'c' });
a.insert_or_assign(1, 'd'); // a 中 1 对应 'd'
emplace
原位构造元素
定义:
template< class... Args >
std::pair<iterator,bool> emplace( Args&&... args );;
std::unordered_map<std::string, std::string> m;
// 使用 pair 的移动构造函数
m.emplace(std::make_pair(std::string("a"), std::string("a")));
// 使用 pair 的转换移动构造函数
m.emplace(std::make_pair("b", "abcd"));
// 使用 pair 的模板构造函数
m.emplace("d", "ddd");
// 使用 pair 的逐片构造函数
m.emplace(std::piecewise_construct,
std::forward_as_tuple("c"),
std::forward_as_tuple(10, 'c'));
// C++17 起,能使用 m.try_emplace("c", 10, 'c');
emplace_hint
- 使用提示原位构造元素
- 返回值
返回指向新插入元素的迭代器。
定义:
template <class... Args>
iterator emplace_hint( const_iterator hint, Args&&... args );
erase
- 从容器擦除指定的元素。
定义:
// 1、移除位于 pos 的元素。
iterator erase( iterator pos );
// 2、移除范围 [first; last) 中的元素。
iterator erase( iterator first, iterator last );
// 3、移除关键等于 key 的元素(若存在一个)。
size_type erase( const key_type& key )
用法:
#include <unordered_map>
#include <iostream>
int main()
{
std::unordered_map<int, std::string> c = {{1, "one"}, {2, "two"}, {3, "three"},
{4, "four"}, {5, "five"}, {6, "six"}};
// 从 c 擦除所有奇数
for(auto it = c.begin(); it != c.end(); )
if(it->first % 2 == 1)
it = c.erase(it);
else
++it;
for(auto& p : c)
std::cout << p.second << ' ';
}
swap
- 交换内容
定义:
void swap( unordered_map& other );
用法:
std::unordered_map<int, char> a1{{1, 'a'}, {2, 'b'}}, a2{{3, 'c'}};
a1.swap(a2);
extract
- 从另一容器释出结点 C++17
定义:
// 解链含 position 所指向元素的结点并返回占有它的结点柄。
node_type extract( const_iterator position );
// 若容器拥有元素而其关键等于 x ,则从容器解链该元素并返回占有它的结点柄。否则,返回空结点柄。
node_type extract( const key_type& x );
merge
- 从另一容器接合结点 C++17
定义:
template<class C2>
void merge( std::unordered_map<Key, C2, Allocator>& source );
template<class C2>
void merge( std::unordered_map<Key, C2, Allocator>&& source );
用法:
std::unordered_map<std::string, int>
p{ {"C", 3}, {"B", 2}, {"A", 1}, {"A", 0} },
q{ {"E", 6}, {"E", 7}, {"D", 5}, {"A", 4} };
p.merge(q);
// p: { {E, 6}, {D, 5}, {A, 1}, {B, 2}, {C, 3} }
// q: { {A, 4} }
查找
at
- 访问指定的元素,同时进行越界检查
T& at( const Key& key );
const T& at( const Key& key ) const;
operator[]
- 访问或插入指定的元素
T& operator[]( const Key& key );
T& operator[]( Key&& key );
std::unordered_map<char, int> letter_counts {{'a', 27}, {'b', 3}, {'c', 1}};
letter_counts['b'] = 42; // 更新既存值
letter_counts['x'] = 9; // 插入新值
for (const auto &pair : letter_counts) {
std::cout << pair.first << ": " << pair.second << '\n';
}
// 统计每个词的出现数
// (首次调用 operator[] 以零初始化计数器)
std::unordered_map<std::string, size_t> word_map;
for (const auto &w : { "this", "sentence", "is", "not", "a", "sentence",
"this", "sentence", "is", "a", "hoax"}) {
++word_map[w];
}
count
- 返回匹配特定键的元素数量
- 返回拥有关键比较等价于指定参数的元素数。
定义:
size_type count( const Key& key ) const;
template< class K >
size_type count( const K& x ) const;
find
- 寻找键等于 key 的的元素
- 返回值
指向键等于 key 的元素的迭代器。若找不到这种元素,则返回尾后(见 end() )迭代器。
定义:
iterator find( const Key& key );
const_iterator find( const Key& key ) const;
用法:
std::unordered_map<int,char> example = {{1,'a'},{2,'b'}};
auto search = example.find(2);
if (search != example.end()) {
std::cout << "Found " << (*search) << '\n';
} else {
std::cout << "Not found\n";
}
contains
- 检查容器是否含有带特定键的元素 C++20
- 若有这种元素则返回 true ,否则返回 false
定义:
bool contains( const Key& key ) const;
template< class K > bool contains( const K& x ) const;
用法:
std::unordered_map<int,char> example = {{1,'a'},{2,'b'}};
for(int x: {2, 5}) {
if(example.contains(x)) {
std::cout << x << ": Found\n";
} else {
std::cout << x << ": Not found\n";
}
}
equal_range
- 返回匹配特定键的元素范围
- 返回容器中所有键等于 key 的元素范围。范围以二个迭代器定义,第一个指向所需范围的首元素,而第二个指向范围的尾后一位元素
定义:
std::pair<iterator,iterator> equal_range( const Key& key );
std::unordered_map<int,char> map = {{1,'a'},{1,'b'},{1,'d'},{2,'b'}};
auto range = map.equal_range(1);
for (auto it = range.first; it != range.second; ++it) {
std::cout << it->first << ' ' << it->second << '\n';
}
// 输出: 1 a
桶接口
begin、cbegin
- 返回一个迭代器,指向指定的桶的开始
local_iterator begin( size_type n );
const_local_iterator begin( size_type n ) const;
const_local_iterator cbegin( size_type n ) const;
end、cend
- 返回一个迭代器,指向指定的桶的末尾
local_iterator end( size_type n );
(C++11 起)
const_local_iterator end( size_type n ) const;
const_local_iterator cend( size_type n ) const;
bucket_count
- 返回桶数
size_type bucket_count() const;
max_bucket_count
- 返回桶的最大数量
size_type max_bucket_count() const;
bucket_size
- 返回下标为 n 的桶中的元素数
size_type bucket_size( size_type n ) const;
bucket
- 返回带有特定键的桶
size_type bucket( const Key& key ) const;
哈希策略
load_factor
- 返回每个桶元素的平均数,即 size() 除以 bucket_count()
float load_factor() const;
max_load_factor
- 管理最大加载因子(每个桶的平均元素数)。若加载因子超出此阈值,则容器自动增加桶数。
// 返回最大加载因子
float max_load_factor() const;
// 设置最大加载因子为 ml
void max_load_factor( float ml );
rehash
- 设置桶数为 count 并重哈希容器,即考虑桶总数已改变,再把元素放到适当的桶中。
- 若新的桶数使加载因子大于最大加载因子( count < size() / max_load_factor() ),则新桶数至少为 size() / max_load_factor()
void rehash( size_type count );
reserve
- 设置桶数为适应至少 count 个元素,而不超出最大加载因子所需的数,并重哈希容器,即考虑桶数已更改后将元素放进适合的桶。等效地调用 rehash(std::ceil(count / max_load_factor())) 。
void reserve( size_type count );
观察器
hash_function
- 返回对关键哈希的函数
hasher hash_function() const;
key_eq
- 返回比较关键相等性的函数
key_equal key_eq() const;
非成员函数
operator==
- 比较 unordered_map 中的值
定义:
template< class Key, class Hash, class KeyEqual, class Allocator >
bool operator==( const std::unordered_map<Key,Hash,KeyEqual,Allocator>& lhs,
const std::unordered_map<Key,Hash,KeyEqual,Allocator>& rhs );
用法:
std::unordered_map<int, char> alice{{1, 'a'}, {2, 'b'}};
std::unordered_map<int, char> bob{{1, 'a'}, {3, 'c'}};
std::unordered_map<int, char> eve{1, 'a'}, {2, 'b'}};
// 比较不相等的容器
std::cout << "alice == bob returns " << (alice == bob) << std::endl; //输出 false
// 比较相等的容器
std::cout << "alice == eve returns " << (alice == eve) << std::endl; //输出 true
std::swap
- 为 std::unordered_map 特化 std::swap 算法。交换 lhs 与 rhs 的内容。调用 lhs.swap(rhs) 。
定义:
template< class Key, class T, class Hash, class KeyEqual, class Alloc >
void swap( std::unordered_map<Key,T,Hash,KeyEqual,Alloc>& lhs,
std::unordered_map<Key,T,Hash,KeyEqual,Alloc>& rhs ););
用法:
std::unordered_map<int, char> alice{{1, 'a'}, {2, 'b'}, {3, 'c'}};
std::unordered_map<int, char> bob{{7, 'Z'}, {8, 'Y'}, {9, 'X'}, {10, 'W'}};
//交换容器
std::swap(alice,bob);
//交换后:alice : 7 8 9 10 bob : 1 2 3
erase_if(std::unordered_map)
- 擦除所有满足特定判别标准的元素(C++ 20)
定义:
template< class Key, class T, class Hash, class KeyEqual, class Alloc, class Pred >
typename std::unordered_map<Key,T,Hash,KeyEqual,Alloc>::size_type
erase_if(std::unordered_map<Key,T,Hash,KeyEqual,Alloc>& c, Pred pred);
用法:
std::unordered_map<int, char> data {{1, 'a'},{2, 'b'},{3, 'c'},{4, 'd'},
{5, 'e'},{4, 'f'},{5, 'g'},{5, 'g'}};
const auto count = std::erase_if(data, [](const auto& item) {
auto const& [key, value] = item;
return (key & 1) == 1;
});