莱芜摩托车网站,wordpress 三一重工,肇庆seo推广公司,大连网站设计九必选仟亿科技1 std::multiset 概述
std::multiset 是 C STL#xff08;标准模板库#xff09;中的一个容器#xff0c;它定义在头文件set中。std::multiset 是一个多重集合容器#xff0c;允许存储重复的元素键值#xff0c;并且这些元素键值按照特定的严格弱排序准则进行排序…1 std::multiset 概述
std::multiset 是 C STL标准模板库中的一个容器它定义在头文件set中。std::multiset 是一个多重集合容器允许存储重复的元素键值并且这些元素键值按照特定的严格弱排序准则进行排序。与 set 容器不同multiset 允许插入重复的元素这是它们之间的主要区别。
multiset 的内部实现通常基于红黑树这种平衡二叉搜索树因此元素的搜索、插入和删除操作都具有对数级的时间复杂度。由于这种数据结构特性multiset 的搜索效率非常高可以快速找到某一键值下的所有元素位置。
multiset提供了一系列成员函数来操作容器中的元素包括插入数据insert、删除数据erase、查找数据find、清空数据clear、判空empty、获取有效元素的大小size、获取键值中查找元素的个数count等。此外它还提供了反向迭代器rbegin和rend可以用于反向遍历容器中的元素。
需要注意的是multiset 中元素的 value 也会识别它组成的键值对但元素的 value 在容器中是不能被修改的。因此multiset 更适用于需要存储重复元素且需要保持元素有序的场景。然而如果插入和删除操作非常频繁multiset 可能不是最佳选择因为每次插入或删除都可能导致树的重新平衡从而影响性能。
1.1 std::multiset 的内部实现
std::multiset 的内部实现主要基于红黑树这种数据结构。红黑树是一种自平衡的二叉搜索树通过着色和特定的调整规则来保持树的平衡从而在动态数据插入、删除和查找过程中保持相对高效的性能。
在std::multiset 中红黑树的特性使得元素总是保持有序。每个节点存储一个元素并且满足二叉搜索树的性质对于每个节点其左子树中的所有元素都小于该节点其右子树中的所有元素都大于该节点。此外红黑树还通过颜色和旋转操作来维护树的平衡确保树的深度不会过大从而保证了操作的效率。
由于红黑树的这些特性std::multiset 的插入、删除和查找操作都能保持对数级的时间复杂度即 O(log n)其中n是容器中元素的数量。这使得 std::multiset 在处理大量数据时仍能保持高效的性能。
以下是一些关于 std::multiset 内部实现中红黑树数据结构的关键点
1节点结构 红黑树的每个节点包含多个信息包括元素的值、节点的颜色红色或黑色、指向左子节点和右子节点的指针。节点颜色的信息对于维护树的平衡性至关重要。
2性质 红黑树满足以下五个关键性质这些性质保证了树的平衡性和搜索效率
每个节点要么是红色要么是黑色。根节点是黑色。所有叶子节点NIL 或空节点通常不显式表示是黑色。如果一个节点是红色的则它的两个子节点都是黑色从每个叶子到根的所有路径上不能有两个连续的红色节点。对于每个节点从该节点到其所有后代叶子节点的简单路径上均包含相同数目的黑色节点。
3插入操作 当向 multiset 中插入一个新元素时首先会像普通的二叉搜索树一样找到新元素应该插入的位置然后执行插入操作。插入后可能需要通过颜色调整和旋转操作来重新平衡树以满足红黑树的性质。
4删除操作 删除操作相对复杂一些因为需要确保在删除节点后树仍然保持平衡。删除操作可能涉及节点的合并、颜色的更改以及树的旋转。
5查找操作 由于红黑树是一种二叉搜索树因此查找操作与普通的二叉搜索树类似。从根节点开始根据节点的值和搜索的键值进行比较决定是向左子树还是向右子树递归查找直到找到目标元素或确定元素不存在。
通过红黑树的这些内部实现机制std::multiset能够高效地维护元素的排序状态并支持快速的插入、删除和查找操作。
1.2 std::multiset 的性能特点
std::multiset 的性能特点主要体现在以下几个方面
1有序性 std::multiset 是一个有序集合容器它根据元素的键值自动进行排序。这种有序性使得元素可以按照特定的顺序进行存储和检索从而方便了对元素的排序和查找操作。
2插入与删除的对数级复杂度 由于 std::multiset 内部采用红黑树作为数据结构因此其插入和删除操作的时间复杂度都是对数级的即 O(log n)其中 n 是容器中元素的数量。这意味着无论容器中有多少元素插入和删除操作的效率都能保持相对稳定不会随着元素数量的增加而显著下降。
3高效的查找性能 同样得益于红黑树的特性std::multiset 的查找操作也具有对数级的时间复杂度。这使得在大量元素中快速定位到特定元素成为可能提高了程序的执行效率。
4允许重复元素 与 std::set 不同std::multiset 允许存储重复的元素。这意味着在同一个 multiset 容器中可以有多个具有相同键值的元素存在。这一特性使得 multiset 在某些需要处理重复元素的场景中非常有用。
5空间消耗 由于 std::multiset 使用红黑树作为内部数据结构而红黑树在维护平衡的过程中可能需要额外的空间来存储节点的颜色和进行旋转操作。因此相对于其他简单的数据结构如数组或链表multiset 的空间消耗可能会稍高一些。但需要注意的是这种空间消耗是为了换取更高的操作效率而付出的代价。
需要注意的是虽然 std::multiset 具有上述性能特点但在某些特定场景下可能并不是最优选择。例如如果需要进行频繁的插入和删除操作并且不关心元素的顺序那么使用其他数据结构如哈希表可能会更加高效。
2 std::multiset 的基本使用
2.1 std::multiset 的声明与初始化
声明 首先需要包含set头文件以使用 std::multiset
#include set
#include string // 声明一个整数类型的 multiset
std::multisetint vals;// 声明一个字符串类型的 multiset
std::multisetstd::string strs;// 声明一个自定义类型的 multiset
struct MyStruct
{int id;std::string name;
};
std::multisetMyStruct myStructs;初始化 可以使用多种方法来初始化 std::multiset。
1默认初始化 创建一个空的 std::multiset 容器。
std::multisetint vals; // 空的 multiset2使用初始化列表 在声明时直接使用初始化列表来添加元素元素会按照排序顺序插入。
std::multisetint vals { 2, 1, 3, 3, 4, 5 };
// vals 现在包含元素1, 2, 3, 3, 4, 53使用迭代器或范围构造 使用另一个容器的迭代器或范围来初始化 std::multiset。
std::vectorint vec { 2, 1, 3, 3, 4, 5 };
std::multisetint vals(vec.begin(), vec.end());
// vals 现在包含元素1, 2, 3, 3, 4, 54复制初始化 使用另一个 std::multiset 来初始化新的 std::multiset。
std::multisetint firstSet { 2, 1, 3, 3, 4, 5 };
std::multisetint secondSet(firstSet); // 复制初始化
// secondSet 现在包含元素1, 2, 3, 3, 4, 55移动初始化 使用另一个 std::multiset 的移动构造函数来初始化新的 std::multiset。
std::multisetint firstSet { 2, 1, 3, 3, 4, 5 };
std::multisetint secondSet(std::move(firstSet)); // 移动初始化
// secondSet 现在包含元素1, 2, 3, 3, 4, 5
// firstSet 现在是一个空的 multiset2.2 std::multiset 的大小与容量
std::multiset 中与大小与容量相关的方法有如下几种empty() const; 检查 multiset 是否为空。size() const; 返回 multiset 中的元素数量。max_size() const; 返回 multiset 可能包含的最大元素数量。
如下为样例代码
#include iostream
#include set int main()
{// 创建一个空的 std::multiset std::multisetint mySet;// 检查 multiset 是否为空并输出信息 if (mySet.empty()) {std::cout The multiset is empty. std::endl;}// 向 multiset 中插入一些元素 mySet.insert(5);mySet.insert(2);mySet.insert(9);mySet.insert(9);mySet.insert(1);// 再次检查 multiset 是否为空并输出信息 if (!mySet.empty()) {std::cout The multiset is not empty. std::endl;}// 获取 multiset 的大小并输出信息 std::cout Size of the multiset: mySet.size() std::endl;// 获取 multiset 可能包含的最大元素数量并输出信息 std::cout Maximum possible size of the multiset: mySet.max_size() std::endl;return 0;
}上面代码的输出为
The multiset is empty.
The multiset is not empty.
Size of the multiset: 5
Maximum possible size of the multiset: 576460752303423487在上面代码中首先创建了一个空的 std::multiset并使用 empty() 方法来检查它是否为空。然后向 multiset 中插入了一些元素并再次使用 empty() 方法来确认它现在不再为空。接着使用 size() 方法来获取 multiset 中的元素数量并输出它。最后使用 max_size() 方法来获取 multiset 可能包含的最大元素数量。
注意std::multiset 的 max_size() 方法通常返回的是一个非常大的数字代表理论上的最大大小限制这通常比实际可用的内存要大得多。在实际使用中由于内存限制可能无法接近这个理论上的最大值。
2.3 std::multiset 的构造函数与析构函数
构造函数 std::multiset 有多个构造函数允许以不同的方式创建 multiset 对象。下面是一些常用的构造函数
std::multiset s;: 默认构造函数创建一个空的 multiset。std::multiset s(const std::multiset other);: 复制构造函数创建一个与 other 相同的 multiset。std::multiset s(std::multiset other);: 移动构造函数创建一个与 other 内容相同的 multiset并将 other 置于有效但未定义的状态C11 新加入。std::multiset s(const_iterator first, const_iterator last);: 范围构造函数使用迭代器 first 和 last 指定的元素范围来创建 multiset。std::multiset s(std::initializer_list init);: 使用初始化列表来创建 multisetC11 新加入。
析构函数
~multiset(): 析构函数释放 multiset 中的所有元素。
如下为样例代码
#include iostream
#include set
#include vector int main()
{// 使用默认构造函数创建一个空的 multiset std::multisetint emptySet;std::cout Empty multiset size: emptySet.size() std::endl;// 使用初始化列表构造函数创建一个 multiset std::multisetint initListSet{ 1, 2, 3, 3, 4, 5 };std::cout Init list multiset: ;for (int num : initListSet) {std::cout num ;}std::cout std::endl;// 使用复制构造函数创建一个与 initListSet 相同的 multiset std::multisetint copiedSet(initListSet);std::cout Copied multiset: ;for (int num : copiedSet) {std::cout num ;}std::cout std::endl;// 创建一个 vector 并使用范围构造函数创建一个 multiset std::vectorint vec{ 6, 7, 7, 8, 9, 10 };std::multisetint rangeSet(vec.begin(), vec.end());std::cout Range multiset: ;for (int num : rangeSet) {std::cout num ;}std::cout std::endl;// 使用移动构造函数从另一个 multiset 移动元素创建一个新的 multiset std::multisetint movingSet(std::move(initListSet));std::cout Moving multiset: ;for (int num : movingSet) {std::cout num ;}std::cout std::endl;// 验证原始 initListSet 已被移动构造函数清空 if (initListSet.empty()) {std::cout initListSet is now empty after moving construction. std::endl;}else {std::cout initListSet still contains elements after moving construction. std::endl;}return 0;
}上面代码的输出为
Empty multiset size: 0
Init list multiset: 1 2 3 3 4 5
Copied multiset: 1 2 3 3 4 5
Range multiset: 6 7 7 8 9 10
Moving multiset: 1 2 3 3 4 5
initListSet is now empty after moving construction.上面代码展示了如何使用 std::multiset 的不同构造函数来创建 multiset 对象。每种构造函数都用于创建一个具有不同特性的 multiset。另外还展示了如何使用迭代器范围和初始化列表来构造 multiset。
注意std::multiset 的析构函数是自动调用的当 multiset 对象离开其作用域时它会自动释放其分配的内存。上面代码没有显式调用析构函数因为 C 的内存管理会自动处理这些事项。
3 std::multiset 的元素操作
3.1 std::multiset 元素的访问与修改
在 std::multiset 中元素的访问和修改有一些特定的方法。由于 std::multiset 是一个有序的集合其元素总是按照某种排序规则通常是小于比较进行排序并且允许重复的元素。因此访问和修改元素的方式与其他容器如 std::vector 或 std::list略有不同。
3.1.1 访问元素
使用迭代器访问 可以使用迭代器来访问 std::multiset 中的元素。迭代器提供了对容器中元素的直接访问。
std::multisetint mySet { 1, 2, 3, 3, 4, 5 };
for (std::multisetint::iterator it mySet.begin(); it ! mySet.end(); it) {std::cout *it ; // 输出1 2 3 3 4 5
}使用 find 方法访问 在 std::multiset 中由于允许存储重复的元素find 方法只能找到第一个与给定键值相等的元素。如果你想要访问所有与给定键值相等的元素你需要使用 find 方法结合迭代器来遍历这些元素。
以下是一个示例展示了如何使用 find 方法找到 std::multiset 中的第一个重复元素并通过迭代器遍历所有与给定键值相等的元素
#include iostream
#include set int main()
{std::multisetint mySet{ 1, 2, 2, 3, 5, 5, 5 };int valueToFind 5;// 使用 find 方法找到第一个与给定键值相等的元素 auto it mySet.find(valueToFind);// 检查是否找到了元素 if (it ! mySet.end()) {std::cout Found valueToFind : ;// 遍历所有与给定键值相等的元素 do {std::cout *it ;} while (it ! mySet.end() *it valueToFind);std::cout std::endl;}else {std::cout valueToFind not found in the multiset. std::endl;}return 0;
}上面代码的输出为
Found 5: 5 5 5在这个示例中首先使用 find 方法找到了第一个值为 5 的元素。然后进入一个 do-while 循环在循环内部首先打印当前迭代器的值然后递增迭代器。循环继续的条件是迭代器没有到达 mySet.end() 并且当前迭代器的值仍然等于要查找的值。这样就能遍历并打印出所有与给定键值相等的元素。
注意这种方法假设 std::multiset 是按升序排序的因此可以简单地通过递增迭代器来遍历所有相等的元素。如果 std::multiset 是按降序排序的那么你需要递减迭代器来遍历所有相等的元素。 使用 lower_bound 和 upper_bound 访问 这两个方法可以用来查找集合中第一个不小于或大于给定值的元素。它们通常用于访问某个范围内的元素。
std::multisetint mySet { 1, 2, 3, 3, 4, 5 };
std::multisetint::iterator lower mySet.lower_bound(3); // 指向3
std::multisetint::iterator upper mySet.upper_bound(4); // 指向4
while (lower ! upper) {std::cout *lower ; // 输出3 3 4lower;
}3.1.2 修改元素
由于 std::multiset 中的元素是常量的const不能直接修改它们的值。如果想要修改具有特定键值的所有元素则需要遍历 multiset 并找到所有匹配的元素然后对每个元素执行删除和插入操作。
如下为样例代码
#include iostream
#include set int main()
{std::multisetint mySet{ 1, 2, 2, 3, 5, 5, 5 };int oldValue 5;int newValue 6;// 遍历并修改所有与给定键值相等的元素 while (true) {auto it mySet.find(oldValue);if (it mySet.end()) {// 没有更多匹配的元素了 break;}// 删除旧元素 mySet.erase(it);// 插入新元素 mySet.insert(newValue);}// 打印修改后的 multiset for (const auto elem : mySet) {std::cout elem ;}std::cout std::endl;return 0;
}上面代码的输出为
1 2 2 3 6 6 6注意修改 std::multiset 中的元素可能会导致容器重新排序这可能会影响性能特别是在大型容器中。因此在性能关键的场景中需要仔细考虑如何有效地管理集合中的元素。
3.2 std::multiset 元素的插入操作
std::multiset 中与元素插入操作相关的方法有如下几种
insert(const value_type value); 插入一个元素。insert(std::initializer_listvalue_type init); 使用初始化列表插入元素。emplace(const args… args); 在 multiset 中就地构造一个元素。
如下为样例代码
#include iostream
#include set
#include initializer_list int main()
{std::multisetint mySet;// 使用 insert(const value_type value) 插入一个元素 mySet.insert(1);// 使用 insert(std::initializer_listvalue_type init) 使用初始化列表插入元素 mySet.insert({ 2, 3, 3, 4 });// 使用 emplace(const args... args) 在 multiset 中就地构造一个元素 mySet.emplace(5);mySet.emplace(6);// 打印 multiset 中的所有元素 for (const auto elem : mySet) {std::cout elem ;}std::cout std::endl;return 0;
}上面代码的输出为
1 2 3 3 4 5 6上述代码演示了如何使用 std::multiset 的各种插入方法来添加元素。首先使用 insert(const value_type value) 方法插入一个元素 1。接着使用 insert(std::initializer_listvalue_type init) 方法通过初始化列表一次性插入了四个元素 2、3、3 和 4。最后使用 emplace(const args… args) 方法就地构造并插入了两个元素 5 和 6。
emplace 方法允许直接传递构造函数的参数给 multiset而不是先构造一个对象再插入。这可以减少不必要的拷贝或移动操作特别是对于复杂类型或资源密集型对象来说可以提高性能。这个例子简单地插入了 int 类型的元素因此性能提升不明显但对于更复杂的类型来说使用 emplace 会更加高效。
需要注意的是由于 std::multiset 是基于排序的集合插入元素的顺序不会影响到最终集合中元素的顺序元素会按照它们的键值自动排序。
3.3 std::multiset 元素的删除操作
std::multiset 中与元素删除操作相关的方法有如下几种
erase(const key_type k); 删除键为 k 的元素。erase(const_iterator position); 删除指定位置的元素。erase(const_iterator first, const_iterator last); 删除一个元素范围。clear(); 删除 multiset 中的所有元素。
如下为样例代码
#include iostream
#include set int main()
{std::multisetint mySet{ 1, 2, 2, 3, 4, 4, 5 };// 打印初始的 multiset std::cout Initial multiset: ;for (const auto elem : mySet) {std::cout elem ;}std::cout std::endl;// 使用 erase(const key_type k); 删除键为 k 的元素 mySet.erase(4); // 这将删除所有键为 4 的元素 // 打印删除后的 multiset std::cout After erasing 4: ;for (const auto elem : mySet) {std::cout elem ;}std::cout std::endl;// 使用 erase(const_iterator position); 删除指定位置的元素 auto it mySet.find(2); // 找到键为 2 的元素 if (it ! mySet.end()) {mySet.erase(it); // 删除找到的第一个键为 2 的元素 }// 打印删除后的 multiset std::cout After erasing one 2: ;for (const auto elem : mySet) {std::cout elem ;}std::cout std::endl;// 使用 erase(const_iterator first, const_iterator last); 删除一个元素范围 it mySet.find(2); // 再次找到键为 2 的元素 if (it ! mySet.end()) {it; // 移动到下一个元素如果有的话 mySet.erase(mySet.find(2), it); // 删除从第一个 2 到下一个元素之前的所有元素 }// 打印删除后的 multiset std::cout After erasing range of 2s: ;for (const auto elem : mySet) {std::cout elem ;}std::cout std::endl;// 使用 clear(); 删除 multiset 中的所有元素 mySet.clear();// 打印清空后的 multiset std::cout After clearing the multiset: ;for (const auto elem : mySet) {std::cout elem ;}std::cout std::endl;return 0;
}上面代码的输出为
Initial multiset: 1 2 2 3 4 4 5
After erasing 4: 1 2 2 3 5
After erasing one 2: 1 2 3 5
After erasing range of 2s: 1 3 5
After clearing the multiset:上面代码展示了如何使用 std::multiset 的不同删除操作。首先它创建了一个包含一些整数的 std::multiset并输出了原始内容。然后它使用 erase(const key_type k) 删除了指定键的所有元素并输出了删除后的内容。接着它使用 erase(const_iterator position) 删除了一个指定位置的元素并再次输出了内容。之后它使用 erase(const_iterator first, const_iterator last) 删除了一个元素范围并输出了更新后的内容。最后它使用 clear() 清空了整个 std::multiset并输出了最终为空的内容以及确认 multiset 大小的输出。
3.4 std::multiset 元素的查找操作
std::multiset 中与查找操作的方法有如下几种
find(const key_type k); 查找键为 k 的元素并返回指向它的迭代器。count(const key_type k); 返回键为 k 的元素的数量对于 multiset此值始终为有可能大于 1。lower_bound(const key_type k); 返回指向第一个不小于 k 的元素的迭代器。upper_bound(const key_type k); 返回指向第一个大于 k 的元素的迭代器。equal_range(const key_type k); 返回一个包含键为 k 的所有元素的迭代器对。
如下为样例代码
#include iostream
#include set int main()
{std::multisetint mySet{ 1, 2, 3, 3, 4, 5 };// 使用 find(const key_type k); 查找键为 k 的元素 auto it mySet.find(3);if (it ! mySet.end()) {std::cout Found 3 std::endl;}else {std::cout 3 not found in the multiset. std::endl;}// 使用 count(const key_type k); 返回键为 k 的元素的数量 int countOfThree mySet.count(3);std::cout Number of 3s in the multiset: countOfThree std::endl;// 使用 lower_bound(const key_type k); 返回指向第一个不小于 k 的元素的迭代器 auto lower mySet.lower_bound(3);std::cout Lower bound of 3 is: *lower std::endl;// 使用 upper_bound(const key_type k); 返回指向第一个大于 k 的元素的迭代器 auto upper mySet.upper_bound(3);std::cout Upper bound of 3 is: *upper std::endl;// 使用 equal_range(const key_type k); 返回一个包含键为 k 的所有元素的迭代器对 auto range mySet.equal_range(3);std::cout Range of 3s in the multiset: ;for (auto it range.first; it ! range.second; it) {std::cout *it ;}std::cout std::endl;return 0;
}上面代码的输出为
Found 3
Number of 3s in the multiset: 2
Lower bound of 3 is: 3
Upper bound of 3 is: 4
Range of 3s in the multiset: 3 3在这个样例中首先使用 find 方法查找一个特定的元素并输出它是否找到以及找到的元素的值。接着使用 count 方法来检查一个元素是否存在于集合中。
然后使用 lower_bound 方法来查找集合中第一个不小于给定键的元素。如果这样的元素存在就输出它否则输出一个消息说明所有元素都大于给定的键。
接着使用 upper_bound 方法来查找集合中第一个大于给定键的元素。如果这样的元素存在就输出它否则输出一个消息说明没有元素大于给定的键。
最后使用 equal_range 方法来查找给定键的所有元素。随后遍历返回的迭代器范围并输出所有等于给定键的元素。
3.5 std::multiset 元素的遍历删除
如果需要在遍历过程中逐个删除元素可以使用 std::multiset::erase 方法结合普通的循环但每次删除元素后都需要更新迭代器。以下是一个逐个删除特定元素的例子
如下为样例代码
#include iostream
#include set int main()
{std::multisetint vals { 1, 2, 3, 3, 4, 5, 6 };auto it vals.begin();while (it ! vals.end()) {if ((*it) % 2 0) {it vals.erase(it); // erase 返回下一个有效元素的迭代器 }else {it; // 继续到下一个元素 }}// 输出结果 for (const auto elem : vals) {std::cout elem ;}return 0;
}上面代码的输出为
1 3 3 5在上面代码中使用一个循环来遍历 multiset并在每次迭代中检查当前元素是否满足删除条件。如果满足条件则使用 erase 方法删除该元素并更新迭代器。如果不满足条件则简单地递增迭代器以继续遍历。
注意在删除元素后迭代器 it 会被 erase 方法更新为指向被删除元素之后的位置因此在下一次循环迭代中it 仍然有效。
4 std::multiset 的迭代器
4.1 std::multiset 迭代器的基本使用
std::multiset 中与迭代器相关的方法有如下几种
begin(): 返回一个指向容器中第一个元素的迭代器。end(): 返回一个指向容器中最后一个元素之后位置的迭代器。rbegin(): 返回一个指向容器中最后一个元素的反向迭代器。rend(): 返回一个指向容器中第一个元素之前位置的反向迭代器。cbegin(), cend(), crbegin(), crend(): 与上述类似但返回的是常量迭代器或常量反向迭代器。
如下为样例代码
#include iostream
#include set int main()
{// 创建一个 std::multiset 并插入一些元素 std::multisetint mySet { 5, 2, 9, 1, 5, 6 };// 使用 begin() 和 end() 遍历 multiset正向遍历 std::cout Forward traversal multiset:\n;for (auto it mySet.begin(); it ! mySet.end(); it) {std::cout *it ;}std::cout std::endl;// 使用 cbegin() 和 cend() 遍历 multiset常量正向遍历 std::cout Constant forward traversal multiset:\n;for (const auto it : mySet) {std::cout it ;}std::cout std::endl;// 使用 rbegin() 和 rend() 遍历 multiset反向遍历 std::cout Reverse traversal multiset:\n;for (auto rit mySet.rbegin(); rit ! mySet.rend(); rit) {std::cout *rit ;}std::cout std::endl;// 使用 crbegin() 和 crend() 遍历 multiset常量反向遍历 std::cout Constant reverse traversal multiset:\n;for (auto rit mySet.crbegin(); rit ! mySet.crend(); rit) {std::cout *rit ;}std::cout std::endl;return 0;
}上面代码的输出为
Forward traversal multiset:
1 2 2 5 5 6 9
Constant forward traversal multiset:
1 2 2 5 5 6 9
Reverse traversal multiset:
9 6 5 5 2 2 1
Constant reverse traversal multiset:
9 6 5 5 2 2 1这个样例展示了如何使用不同类型的迭代器来遍历 std::multiset。begin() 和 end() 用于正向遍历rbegin() 和 rend() 用于反向遍历。同时cbegin(), cend(), crbegin(), 和 crend() 是常量版本的迭代器它们用于保证在遍历过程中不会修改容器中的元素。
4.2 std::multiset 迭代器使用的注意事项
在使用 std::multiset 的迭代器时有几个重要的注意事项需要牢记
1有效性 一旦迭代器指向的元素被删除或移动迭代器就失效了。在删除或修改 std::multiset 中的元素后必须确保不再使用失效的迭代器。
2常量迭代器 std::multiset 提供了常量迭代器const_iterator这些迭代器不能用来修改元素的值。
3遍历过程中删除元素 在遍历 std::multiset 的过程中直接删除元素会导致迭代器失效。如果需要删除元素通常的做法是使用一个单独的容器如 std::vector 或另一个 std::multiset来保存要删除的键然后在遍历结束后使用 erase 方法删除这些键。
4end() 方法返回的迭代器 end() 方法返回的迭代器指向的是容器中的“尾后”位置即最后一个元素之后的位置。这个迭代器不能被解引用。在遍历容器时应该小心不要试图访问 end() 返回的迭代器。
5修改键值 std::multiset 中的元素是根据键值排序的。如果通过迭代器修改了元素的键值这将会破坏容器的排序特性。通常情况下不应该这样做实际上这么做也无法通过编译。如果需要改变元素的键值应该先删除原元素然后插入新的元素。