C++ unordered_set/multiset使用
unordered_set
概述
- unordered_set 与 unordered_multiset 都定义于头文件<unordered_set>
- unordered_set 是含有 Key 类型唯一对象集合的关联容器。搜索、插入和移除拥有平均常数时间复杂度。
- unordered_multiset 是含有 Key 类型不唯一对象集合的关联容器。
- unordered_set 与 unordered_multiset 成员函数及非成员函数使用方法相同,只是在 insert 函数内部,unordered_set 调用 insert_unique 函数不允许键重复,而 unordered_multiset 调用 insert_equal 函数允许键重复。
- 在内部,元素并不以任何特别顺序排序,而是组织进桶中。元素被放进哪个桶完全依赖其值的哈希。这允许对单独元素的快速访问,因为哈希一旦确定,就准确指代元素被放入的桶。
类模板:
template<
class Key,
class Hash = std::hash<Key>,
class KeyEqual = std::equal_to<Key>,
class Allocator = std::allocator<Key>
> class unordered_set;
创建unordered_set
构造函数
- 与set大致相同。
opertor=
- 赋值给容器
定义:
unordered_set& operator=( const unordered_set& other ); // 复制赋值运算符。
unordered_set& operator=( unordered_set&& other ); // 移动赋值运算符。
unordered_set& operator=( std::initializer_unordered_set<T> iunordered_set ); // 以 initializer_unordered_set iunordered_set 所标识者替换内容。
用法:
std::unordered_set<int> nums1 {3, 1, 4, 6, 5, 9};
std::unordered_set<int> nums2;
std::unordered_set<int> nums3;
// 从 nums1 复制赋值数据到 nums2
nums2 = nums1;
// 从 nums1 移动赋值数据到 nums3,
nums3 = std::move(nums1);
// initializer_unordered_set 的复制赋值复制数据给 nums1
nums1 = {1, 2, 3};
迭代器
begin\cbegin
- 返回指向 unordered_set 首元素的迭代器。
- cbegin中的c表示const,即返回const_iterator,不允许通过迭代器修改元素。
- 若 unordered_set 为空,则返回的迭代器将等于 end() 。
定义:
iterator begin();
const_iterator cbegin() const noexcept;
end\cend
- 返回指向 unordered_set 末元素后一元素的迭代器。
定义:
iterator end();
const_iterator cend() const noexcept;
容量
empty
- 检查容器是否无元素,即是否 begin() == end() 。
定义:
bool empty() const;
用法:
std::unordered_set<int> v;
bool flag = v.empty(); // 输出 true
size
- 返回容纳的元素数。 即 std::distance(begin(), end()) 。
定义:
size_type size() const;
用法:
std::unordered_set<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_set<int> vi;
std::cout << vi.max_size() << std::endl; // 可能输出 4611686018427387903
std::unordered_set<char> vc;
std::cout << vc.max_size() << std::endl; // 可能输出 18446744073709551615
修改器
clear
- 从容器擦除所有元素。此调用后 size() 返回零。
- 非法化任何指代所含元素的引用、指针或迭代器。任何尾后迭代器亦被非法化。
定义:
void clear();
用法:
std::unordered_set<int> container{1, 2, 3};
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_set<int> a;
a.insert(4);
std::unordered_set<int> b { 7, 8, 9 };
a.insert(b.begin(), b.end());
a.insert({ 1, 2, 3 });
emplace
原位构造元素
定义:
template< class... Args >
std::pair<iterator,bool> emplace( Args&&... args );;
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_set>
#include <iostream>
int main()
{
std::unordered_set<int> c = { 8, 1, 2, 4, 5, 7, 9, 6, 3 };
// 从 c 擦除所有奇数
for (auto it = c.begin(); it != c.end(); )
if (*it % 2 == 1)
it = c.erase(it);
else
++it;
for (int n : c)
std::cout << n << ' ';
}
// c : 8 2 4 6
swap
- 交换内容
定义:
void swap( unordered_set& other );
用法:
std::unordered_set<int> a1{1, 2, 3}, a2{4, 5};
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_set<Key, C2, Allocator>& source );
template<class C2>
void merge( std::unordered_set<Key, C2, Allocator>&& source );
用法:
std::unordered_set<char>
p{ 'C', 'B', 'B', 'A' },
q{ 'E', 'D', 'E', 'C' };
p.merge(q);
// p: { E, D, A, B, C }
// q: { C }
查找
count
- 返回匹配特定键的元素数量
- 返回拥有关键比较等价于指定参数的元素数,因为此容器不允许重复故为 1 或 0。
定义:
size_type count( const Key& key ) const;
find
- 寻找带有特定键的元素
- 返回值
指向键等于 key 的元素的迭代器。若找不到这种元素,则返回尾后(见 end() )迭代器。
定义:
iterator find( const Key& key );
const_iterator find( const Key& key ) const;
用法:
std::unordered_set<int> example = {1, 2, 3, 4};
auto search = example.find(2);
if (search != example.end()) {
std::cout << "Found " << (*search) << '\n';
} else {
std::cout << "Not found\n";
}
contains
- 检查容器是否含有带特定键的元素
- 若有这种元素则返回 true ,否则返回 false
定义:
bool contains( const Key& key ) const;
template< class K > bool contains( const K& x ) const;
用法:
std::unordered_set<int> example = {1, 2, 3, 4};
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 );
桶接口
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
- 返回在特定的桶中的元素数量
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_set 中的值
定义:
template< class Key, class Hash, class KeyEqual, class Allocator >
bool operator==( const std::unordered_set<Key,Hash,KeyEqual,Allocator>& lhs,
const std::unordered_set<Key,Hash,KeyEqual,Allocator>& rhs );
用法:
std::unordered_set<int> alice{1, 2, 3};
std::unordered_set<int> bob{7, 8, 9, 10};
std::unordered_set<int> eve{1, 2, 3};
// 比较不相等的容器
std::cout << "alice == bob returns " << (alice == bob) << std::endl; //输出 false
// 比较相等的容器
std::cout << "alice == eve returns " << (alice == eve) << std::endl; //输出 true
std::swap
- 为 std::unordered_set 特化 std::swap 算法。交换 lhs 与 rhs 的内容。调用 lhs.swap(rhs) 。
定义:
template< class Key, class Hash, class KeyEqual, class Alloc >
void swap( std::unordered_set<Key,Hash,KeyEqual,Alloc>& lhs,
std::unordered_set<Key,Hash,KeyEqual,Alloc>& rhs );
用法:
std::unordered_set<int> alice{1, 2, 3};
std::unordered_set<int> bob{7, 8, 9, 10};
//交换容器
std::swap(alice,bob);
//交换后:alice : 7 8 9 10 bob : 1 2 3
erase_if(std::unordered_set)
- 擦除所有满足特定判别标准的元素(C++ 20)
定义:
template< class Key, class Hash, class KeyEqual, class Alloc, class Pred >
typename std::unordered_set<Key,Hash,KeyEqual,Alloc>::size_type
erase_if(std::unordered_set<Key,Hash,KeyEqual,Alloc>& c, Pred pred);
用法:
std::unordered_set<char> cnt {'1', '2', '3', '5', '6'};
std::erase_if(cnt,
[](char x) { return (x - '0') % 2 == 0; }
);