std::unordered_multiset
介绍
成员函数
非成员函数
介绍
// unordered_multiset 模板定义
template<
class Key,
class Hash = std::hash<Key>,
class KeyEqual = std::equal_to<Key>,
class Allocator = std::allocator<Key>> class unordered_multiset;
namespace pmr {
template <class Key,
class Hash = std::hash<Key>,
class Pred = std::equal_to<Key>>
using unordered_multiset = std::unordered_multiset<Key, Hash, Pred, std::pmr::polymorphic_allocator<Key>>
}
- std::unordered_multiset 介绍摘选自 cppreference.com 中文网 std::unordered_multiset 介绍
- unordered_multiset 是关联容器,含有可能非唯一 Key 类型对象的集合。搜索、插入和移除拥有平均常数时间复杂度
- 元素在内部并不以任何顺序排序,只是被组织到桶中。元素被放入哪个桶完全依赖其值的哈希
- 这允许快速访问单独的元素,因为一旦计算哈希,它就指代放置该元素的准确的桶
- 不要求此容器的迭代顺序稳定(故例如 std::equal 不能用于比较二个 std::unordered_multiset )
- 了关键比较等价(以 key_eq() 为比较器比较相等)的每组元素组成迭代顺序中的相接子范围,它可用 equal_range() 访问
- unordered_multiset可以存储多个相同的数值,unordered_set只能存储一个相同的数值
- 无序容器,值存储的位置可能会变化,所以直接访问元素
成员函数
构造析构
#include <QCoreApplication>
#include <algorithm>
#include <iostream>
#include <string>
#include <unordered_set>
auto Print(const std::string &msg,
const std::unordered_multiset<int, std::hash<int>, std::less<int>,
std::allocator<int>> &lst) {
std::cout << msg << " : ";
for (const auto &pa : lst) {
std::cout << pa << "\t";
}
std::cout << "\n";
}
auto Print(const std::string &msg, const std::unordered_multiset<int> &lst) {
std::cout << msg << " : ";
for (const auto &pa : lst) {
std::cout << pa << "\t";
}
std::cout << "\n";
}
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
using uset_int = std::unordered_multiset<int>;
uset_int s1; //默认构造
Print("s1", s1);
uset_int s2(10); //设置桶数量
Print("s2", s2);
uset_int s3(10, std::hash<int>()); //设置桶数量,哈希散列
Print("s3", s3);
std::unordered_multiset<int, std::hash<int>, std::less<int>> s4(
10, std::hash<int>(), std::less<int>{}); //设置桶数量,哈希散列,比较器
Print("s4", s4);
std::unordered_multiset<int, std::hash<int>, std::less<int>,
std::allocator<int>>
s5(10, std::hash<int>(), std::less<int>(),
std::allocator<int>()); //设置桶数量,哈希散列,比较器,分配器
Print("s5", s5);
uset_int s6(10, std::allocator<int>()); //设置桶数量,分配器
Print("s6", s6);
uset_int s7{1, 2, 3, 4, 5, 6, 5}; //初始化列表
Print("s7", s7);
uset_int s8(s7.begin(), s7.end()); //迭代器初始化
Print("s8", s8);
uset_int s9(s8); //拷贝构造
Print("s9", s9);
uset_int s10(s9, std::allocator<int>());
Print("s10", s10);
uset_int s11(std::move(s10)); //移动构造
Print("s11", s11);
uset_int s12(std::move(s11), std::allocator<int>());
Print("s12", s12);
//析构函数默认
return 0; // a.exec();
}
输出结果:
s1 :
s2 :
s3 :
s4 :
s5 :
s6 :
s7 : 1 2 3 4 5 5 6
s8 : 1 2 3 4 5 5 6
s9 : 1 2 3 4 5 5 6
s10 : 1 2 3 4 5 5 6
s11 : 1 2 3 4 5 5 6
s12 : 1 2 3 4 5 5 6
元素访问
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
using uset_int = std::unordered_multiset<int>;
uset_int s1{1, 2, 3, 4, 5, 6, 5};
std::cout << "s1 : ";
for (const auto &val : s1) {
std::cout << val << "\t";
}
std::cout << "\n";
return 0; // a.exec();
}
输出结果:
s1 : 1 2 3 4 5 5 6
迭代器
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
using uset_int = std::unordered_multiset<int>;
uset_int s1{1, 2, 3, 4, 5, 6, 5};
uset_int::iterator iter = s1.begin();
std::cout << "s1 : ";
for (; iter != s1.end(); ++iter) {
std::cout << *iter << "\t";
}
std::cout << "\n";
uset_int::const_iterator citer = s1.cbegin();
std::cout << "s1 : ";
for (; citer != s1.cend(); ++citer) {
std::cout << *citer << "\t";
}
std::cout << "\n";
return 0; // a.exec();
}
输出结果:
s1 : 1 2 3 4 5 5 6
s1 : 1 2 3 4 5 5 6
容量
auto Print(const std::string &msg, const std::unordered_multiset<int> &lst) {
std::cout << msg << " : ";
for (const auto &pa : lst) {
std::cout << pa << "\t";
}
std::cout << "\n";
}
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
using uset_int = std::unordered_multiset<int>;
uset_int s1{1, 2, 3, 4, 5, 6, 5};
Print("s1", s1);
//检查容器是否为空
std::cout << std::boolalpha << "s1.empty() : " << s1.empty() << std::endl;
std::cout << "s1.size() : " << s1.size() << std::endl; //返回容纳的元素数
std::cout << "s1.max_size() : " << s1.max_size()
<< std::endl; //返回可容纳的最大元素数,和平台有关
return 0; // a.exec();
}
输出结果:
s1 : 1 2 3 4 5 5 6
s1.empty() : false
s1.size() : 7
s1.max_size() : 768614336404564650
修改器
auto Print(const std::string &msg, const std::unordered_multiset<int> &lst) {
std::cout << msg << " : ";
for (const auto &pa : lst) {
std::cout << pa << "\t";
}
std::cout << "\n";
}
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
using uset_int = std::unordered_multiset<int>;
uset_int s1{1, 2, 3, 4, 5, 6, 5};
Print("s1", s1);
s1.clear(); // 清除内容
Print("s1", s1);
s1.insert(20); //插入元素或结点
Print("s1", s1);
s1.emplace(30); //原位构造元素
Print("s1", s1);
s1.emplace_hint(s1.end(), 40); //使用提示原位构造元素
Print("s1", s1);
s1.erase(s1.begin()); //擦除元素
Print("s1", s1);
uset_int s2;
s2.swap(s1);
Print("s1", s1);
Print("s2", s2);
return 0; // a.exec();
}
输出结果:
s1 : 1 2 3 4 5 5 6
s1 :
s1 : 20
s1 : 20 30
s1 : 20 30 40
s1 : 30 40
s1 :
s2 : 30 40
查找
auto Print(const std::string &msg, const std::unordered_multiset<int> &lst) {
std::cout << msg << " : ";
for (const auto &pa : lst) {
std::cout << pa << "\t";
}
std::cout << "\n";
}
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
using uset_int = std::unordered_multiset<int>;
uset_int s1{1, 2, 3, 4, 5, 6, 5, 6};
Print("s1", s1);
// 返回匹配特定键的元素数量
std::cout << "s1.count(1) : " << s1.count(1) << std::endl;
std::cout << "s1.count(5) : " << s1.count(5) << std::endl;
std::cout << "s1.count(6) : " << s1.count(6) << std::endl;
// 寻找带有特定键的元素,返回 key 对应的任意一个值的迭代器
uset_int::const_iterator iter = s1.find(5);
if (iter != s1.cend()) {
std::cout << "s1.find(5) : " << *iter << std::endl;
} else {
std::cout << "s1.find(5) : s1.cend()" << std::endl;
}
// 返回容器中所有键等于 key 的元素范围
// 返回容器中所有键等于 key
// 的元素范围。范围以二个迭代器定义,第一个指向所需范围的首元素,而第二个指向范围的尾后一位元素。
// 返回含有容器中所有键等价于 x 的元素的范围。此重载只有在有限定标识
// Hash::is_transparent 与 KeyEqual::is_transparent
// 均合法并指代类型时才参与重载决议。这假设能用 K 和 Key 类型一起调用这种 Hash
// 还有 KeyEqual 是通透的,进而允许不用构造 Key 的实例就调用此函数
std::pair<uset_int::iterator, uset_int::iterator> pa = s1.equal_range(5);
if (pa.first == s1.end())
std::cout << "pa.first is empty" << std::endl;
else
std::cout << "s1.equal_range(5) first : " << *pa.first << std::endl;
if (pa.second == s1.end())
std::cout << "pa.second is empty" << std::endl;
else
std::cout << "s1.equal_range(5) second : " << *pa.second << std::endl;
return 0; // a.exec();
}
输出结果:
s1 : 1 2 3 4 5 5 6 6
s1.count(1) : 1
s1.count(5) : 2
s1.count(6) : 2
s1.find(5) : 5
s1.equal_range(5) first : 5
s1.equal_range(5) second : 6
非成员函数
auto Print(const std::string &msg, const std::unordered_multiset<int> &lst) {
std::cout << msg << " : ";
for (const auto &pa : lst) {
std::cout << pa << "\t";
}
std::cout << "\n";
}
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
using uset_int = std::unordered_multiset<int>;
uset_int s1{1, 2, 3, 4, 5, 6, 5};
uset_int s2{1, 2, 3, 4, 5, 6, 5};
Print("s1", s1);
Print("s2", s2);
std::cout << std::boolalpha << "s1 == s2 : " << (s1 == s2) << std::endl;
uset_int s3;
std::swap(s3, s2);
Print("s2", s2);
Print("s3", s3);
return 0; // a.exec();
}
输出结果:
s1 : 1 2 3 4 5 5 6
s2 : 1 2 3 4 5 5 6
s1 == s2 : true
s2 :
s3 : 1 2 3 4 5 5 6
桶接口
auto Print(const std::string &msg, const std::unordered_multiset<int> &lst) {
std::cout << msg << " : ";
for (const auto &pa : lst) {
std::cout << pa << "\t";
}
std::cout << "\n";
}
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
using uset_int = std::unordered_multiset<int>;
uset_int s1;
s1.emplace(20);
s1.emplace(5);
s1.emplace(66);
s1.emplace(99);
s1.emplace(66);
s1.emplace(100);
Print("s1", s1);
//返回一个迭代器,指向指定的桶的开始
for (int i = 0; i < s1.bucket_count(); ++i) {
auto iter = s1.begin(i);
if (iter == s1.end(i)) {
std::cout << "s1.end(" << i << ")"
<< "\t";
} else {
for (; iter != s1.end(i); ++iter) {
std::cout << "s1.begin(" << i << ") : " << *iter << "\t";
}
}
}
std::cout << "\n";
//返回一个迭代器,指向指定的桶的开始
for (int i = 0; i < s1.bucket_count(); ++i) {
auto iter = s1.cbegin(i);
if (iter == s1.cend(i)) {
std::cout << "s1.cend(" << i << ")"
<< "\t";
} else {
for (; iter != s1.cend(i); ++iter) {
std::cout << "s1.cbegin(" << i << ") : " << *iter << "\t";
}
}
}
std::cout << "\n";
//返回桶数
std::cout << "s1.bucket_count() : " << s1.bucket_count() << std::endl;
//返回桶的最大数量
std::cout << "s1.max_bucket_count() : " << s1.max_bucket_count() << std::endl;
//返回在特定的桶中的元素数量
for (int i = 0; i < s1.bucket_count(); ++i) {
std::cout << "s1.bucket_size(" << i << ") : " << s1.bucket_size(i) << "\t";
}
std::cout << "\n";
//返回带有特定键的桶,返回关键 key 的桶的下标。始终会在此桶中找到关键等于 key
//的元素(若存在)。返回值仅对 bucket_count() 返回相同值的容器实例合法。
//若 bucket_count() 为零则行为未定义
std::cout << "s1.bucket(1) : " << s1.bucket(1) << std::endl;
std::cout << "s1.bucket(100) : " << s1.bucket(100) << std::endl;
// 键不存在,若存在会分配当前下标的桶
std::cout << "s1.bucket(5000) : " << s1.bucket(5000) << std::endl;
std::cout << "s1.bucket(2) : " << s1.bucket(2) << std::endl;
return 0; // a.exec();
}
输出结果:
s1 : 100 20 5 66 66 99
s1.begin(0) : 5 s1.begin(1) : 100 s1.begin(1) : 20 s1.end(2) s1.end(3) s1.end(4) s1.end(5) s1.begin(6) : 99 s1.begin(7) : 66 s1.begin(7) : 66
s1.cbegin(0) : 5 s1.cbegin(1) : 100 s1.cbegin(1) : 20 s1.cend(2) s1.cend(3) s1.cend(4) s1.cend(5) s1.cbegin(6) : 99 s1.cbegin(7) : 66 s1.cbegin(7) : 66
s1.bucket_count() : 8
s1.max_bucket_count() : 1152921504606846975
s1.bucket_size(0) : 1 s1.bucket_size(1) : 2 s1.bucket_size(2) : 0 s1.bucket_size(3) : 0 s1.bucket_size(4) : 0 s1.bucket_size(5) : 0 s1.bucket_size(6) : 1 s1.bucket_size(7) : 2
s1.bucket(1) : 4
s1.bucket(100) : 1
s1.bucket(5000) : 4
s1.bucket(2) : 7
哈希策略
auto Print(const std::string &msg, const std::unordered_multiset<int> &lst) {
std::cout << msg << " : ";
for (const auto &pa : lst) {
std::cout << pa << "\t";
}
std::cout << "\n";
}
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
using uset_int = std::unordered_multiset<int>;
uset_int s1;
s1.emplace(20);
s1.emplace(5);
s1.emplace(66);
s1.emplace(99);
s1.emplace(66);
s1.emplace(100);
Print("s1", s1);
for (int i = 0; i < s1.bucket_count(); ++i) {
auto iter = s1.begin(i);
if (iter == s1.end(i)) {
std::cout << "s1.end(" << i << ")"
<< "\t";
} else {
for (; iter != s1.end(i); ++iter) {
std::cout << "s1.begin(" << i << ") : " << *iter << "\t";
}
}
}
std::cout << "\n";
//返回每个桶的平均元素数量
std::cout << "s1.load_factor() : " << s1.load_factor() << std::endl;
for (int i = 0; i < s1.bucket_count(); ++i) {
}
//管理每个桶的平均元素数量的最大值
//管理最大加载因子(每个桶的平均元素数)。若加载因子超出此阈值,则容器自动增加桶数
//返回最大加载因子
std::cout << "s1.max_load_factor() : " << s1.max_load_factor() << std::endl;
//设置最大加载因子
s1.max_load_factor(0.9);
std::cout << "s1.max_load_factor() : " << s1.max_load_factor() << std::endl;
//为至少为指定数量的桶预留存储空间并重新生成散列表
s1.rehash(16);
for (int i = 0; i < s1.bucket_count(); ++i) {
auto iter = s1.begin(i);
if (iter == s1.end(i)) {
std::cout << "s1.end(" << i << ")"
<< "\t";
} else {
for (; iter != s1.end(i); ++iter) {
std::cout << "s1.begin(" << i << ") : " << *iter << "\t";
}
}
}
std::cout << "\n";
//为至少为指定数量的元素预留存储空间并重新生成哈希表
s1.reserve(20);
for (int i = 0; i < s1.bucket_count(); ++i) {
auto iter = s1.begin(i);
if (iter == s1.end(i)) {
std::cout << "s1.end(" << i << ")"
<< "\t";
} else {
for (; iter != s1.end(i); ++iter) {
std::cout << "s1.begin(" << i << ") : " << *iter << "\t";
}
}
}
std::cout << "\n";
return 0; // a.exec();
}
输出结果:
s1 : 100 20 5 66 66 99
s1.begin(0) : 5 s1.begin(1) : 100 s1.begin(1) : 20 s1.end(2) s1.end(3) s1.end(4) s1.end(5) s1.begin(6) : 99 s1.begin(7) : 66 s1.begin(7) : 66
s1.load_factor() : 0.75
s1.max_load_factor() : 1
s1.max_load_factor() : 0.9
s1.begin(0) : 5 s1.begin(1) : 20 s1.begin(1) : 100 s1.end(2) s1.end(3) s1.end(4) s1.end(5) s1.begin(6) : 99 s1.begin(7) : 66 s1.begin(7) : 66 s1.end(8) s1.end(9) s1.end(10) s1.end(11) s1.end(12) s1.end(13) s1.end(14) s1.end(15)
s1.begin(0) : 5 s1.begin(1) : 20 s1.end(2) s1.end(3) s1.end(4) s1.end(5) s1.begin(6) : 99 s1.end(7) s1.end(8) s1.end(9) s1.end(10) s1.end(11) s1.end(12) s1.end(13) s1.end(14) s1.end(15) s1.end(16) s1.begin(17) : 100 s1.end(18) s1.end(19) s1.end(20) s1.end(21) s1.end(22) s1.begin(23) : 66 s1.begin(23) : 66 s1.end(24) s1.end(25) s1.end(26) s1.end(27) s1.end(28) s1.end(29) s1.end(30) s1.end(31)