$multiset$ 知识点整理总结
往期内容: STL总目录-超详细
好长时间没有更新了,那今天来水一篇浅谈 $multiset$ 的分享吧。
说实话,我本来不打算写 $multiset$ 的,原因呢主要有两个,其一呢,他没什么太多可说的,因为它和 $set$ 只有很小的差距,再者呢,我懒。。。但是在各位粉丝和俺们机房小朋友的催更和支持下,我决定还是把他写了,方便大家对比理解并更好的使用它们。
下面,正片开始!
(Ps:还没学过 $set$ 的先看这个-> set传送门 )
$multiset$ 与 $set$ 到底有什么区别
如题,想必这是所有人看到 $multiset$ 时脑海里跳出的第一个问题了,这也是我们今天所要讨论和解决的最主要的一个问题,因为 $multiset$ 就是 $set$的一个升级版,只要理解了二者的区别,其他相同的内容直接照搬 $set$ 就好啦。
那他们之间到底有什么区别呢?
我们还是先从字面上看:$multiset$ 只比 $set$ 多了一个 $multi$ 那这个 $multi$ 是什么意思呢?
$multi$ 其实并不是一个英文单词,它只是一个单词的前缀,他的意思是“多种,多数”,比如常见的以 $multi$ 为前缀的单词有
$multiple \qquad adj.多个(人/时间/物 \, 组成)的;数量多的 \quad n.倍数$
$multiply \qquad v.乘,相乘;(使)大量增加$
$multicultural \qquad adj.多元文化的$
因此我习惯于把 $multset$ 成为 $多重集合$ (虽然大家似乎都这么叫?)。那这么说,$multiset$ 就是把多个集合并在一起的一个容器喽?其实,这个 $multi$ 是针对 $set$ 具有的“互异性”的,既然互异性保证了集合中每个元素最多只出现“一次”,那现在 $multi$ 就代表每个元素都可存在“多次”。
下面举一个小栗子,便于大家理解:
假设我们有一个名为 $a$ 的 $set$ 和一个名为 $b$ 的 $multiset$。当我们向 $a$ 和 $b$ 中放入相同的一串数字 $1,3,2,4,2$ 时, $a$ 中存储的内容为 $1, 2, 3, 4$,而 $b$ 中则是 $1, 2, 2, 3, 4$。
代码实现如下:
#include <iostream>
#include <set> //就连头文件都是共用一个呢~
using namespace std;
set<int>::iterator it_a;
multiset<int>::iterator it_b;
int Input[5] = {1, 3, 2, 4, 2};
int main() {
set<int> a(Input, Input + 5);
multiset<int> b(Input, Input + 5);
cout << "a(set)中元素个数为" << a.size() << ",分别为:";
for (it_a = a.begin(); it_a != a.end(); it_a++) {
cout << *it_a << " ";
}
cout << endl;
cout << "b(multiset)中元素个数为" << b.size() << ",分别为:";
for (it_b = b.begin(); it_b != b.end(); it_b++) {
cout << *it_b << " ";
}
return 0;
}
运行结果:
$multiset$ 还有什么特殊的成员函数吗
答案是肯定的,这里我们只介绍一个较为常用的:equal_range
老样子,顾名思义,就是查找“相等范围”喽。
equal_range(val) -> 返回val可被安插的第一个位置和最后一个位置,也就是“元素值==val”的元素区间
特别要注意的是返回值的类型,不难看出,equal_range同时返回了两个值,那么这就意味着,它返回的类型是在一个 $pair$ 中的,而 $pair$ 两个值的类型均为迭代器类型。
光说可能比较难理解,我们结合代码来看一下:
#include <iostream>
#include <set>
using namespace std;
typedef multiset<int>::iterator It;
int main () {
int myints[]= {77,30,16,2,30,30};
multiset<int> mymultiset (myints, myints+6);
//定义一个存储内容为:2,16,30,30,30,77的multiset
pair<It,It> ret = mymultiset.equal_range(30);
//此时ret.first指向的即为multiset中第一个30的位置,而ret.second指向的便是最后一个30的下一个元素的位置
mymultiset.erase(ret.first, ret.second);
//我们可以通过ret中这两个迭代器来清除所有等于30的这一段元素
for (It it = mymultiset.begin(); it != mymultiset.end(); it++) {
cout << *it << " ";
}
//最后的输出结果便是:2,16,77。即所有30都被erase掉了
return 0;
}
$.erase$
补充日期:2021.12.30
感谢 @levelna 的补充!
我们已经知道 $set$ 中的 $.erase(x)$ 能够删除值为 $x$ 的一个元素,那我们不妨把他理解为
删掉所有值为 $x$ 的元素,但是由于 $set$ 所具有的互异性,值为 $x$ 的元素最多只存在一个
那既然 $multiset$ 直接忽略了互异性,那么 $.erase(x)$ 便能充分的发挥它的功能了,即删除所有价值为 $x$ 的元素。
比如:
#include <iostream>
#include <set>
using namespace std;
int Input[5] = {0, 0, 0, 0, 0};
multiset<int> a(Input, Input + 5);
//multiset中所有元素都为0(共5个)
int main() {
cout << a.size() << endl;
a.erase(0);
//删除所有0
cout << a.size() << endl;
//最后里面一个都没了
return 0;
}
运行结果:
所以,总的来说,$multiset$ 只不过是一个特殊的 $set$,实际应用里只要根据题目要求选择更合适的就好了,如果数据不允许重复,那 $set$ 就是更好的选择,反之则应选择 $multiset$ 喽!
那今天就写到这里吧,又水了一篇分享呢
别忘了
# 催更区
101011001101011101010110110101111011110110110000011010110110101011000010110000111010011010101100011001001011001100110001101-------------------------------------------
#催更
机房小朋友
## 来催更QWQ
#催更
# 灌水区
水
水
水
水
1
l
l
l
l
l
i
l
l
l
$\color{#FF0000}{好姐妹来玩水}$
# 学术交流区
交流一下
♂好像multiset的erase(val)会删掉所有等于val的元素?只删一个的话得传入迭代器吧?
嗯是的没错