赞
踩
本文从一名大学生新生的角度出发,简单总结了C++中STL模板set的用法,希望可以帮到任何看到这篇文章的人。
作者的身份是一名普通的大一计科学生,对于cpp的理解浅薄,还请批评指出。
可能这篇文章更适用于初高中的oier~重在如何使用而非严谨的底层原理
其实set翻译过来就是集合,在高中数学我们知道集合具有互异性,也就是同一个元素只会出现一次。
同样的,set 作为c++中STL容器,它的最大特点就是具有互异性,我们一般可以用来快速判断某个元素是否存在。
set正式名字叫做关联容器,它的关联性在于它内部是用红黑树对所有元素排序的
Stop!这里因此就有一个特性:set是默认按升序顺序排序好的
一般来说树结构存在<key,value>形式,其中key用于排序,value为其值,只是在set中value与key
值是一样的,但它仍然属于关联容器
在这里,我们都假设我们声明的set的变量名为P
共有三种方式
①直接创建不带参数
set<typename>Variable_name
eg:
set<int>P
②通过花括号传入初始值
set<typename>Variable_name{x1,x2,x3,……,xn}
eg1.
set<int>P{2,3}
eg2.
set<string>P{"LHP","YYT"}
③从另外一个set中拷贝元素
- set<string> st{"good", "bad", "medium"};
- set<string> st2(st);
在定义set时,我们可以通过传入元素排序规则(set中的第二个参数)来改变排序方式,比如
set<string, greater<string>> st{"good", "bad", "medium"};
在这里greater代表字典序更大的排在前面,我们没传入此参数遍历结果为"bad","good","medium"
而传入了greater规则后结果则为"medium","good","bad".
一种值得一提的构造方式是将STL中的pair与set一同结合起来使用
set<pair<int,int>>P
这样我们便可以判定一对值是否存在于set中(经常可用于判断一个坐标是否已经经过)
注意插入时我们用到make_pair()语句
Set_Name.insert(make_pair(x,y))
要讲这个就得先讲迭代器
set<typename>::iterator it;
set<string>::iterator it;
我们可以简单的将迭代器暂时理解为指针
也因为如此理解,*it代表对应地址的值,因此采用这种方法访问元素
P.begin()返回第一个元素的迭代器
P.end()返回最后一个元素下一个位置的迭代器
因此,想要遍历P,则可以如此写
- set<string>::iterator it;
- for(it=P.begin();it!=P.end();it++){
- cout<<*it<<endl;
- }
还可以利用auto自动识别数据类型来偷懒,见下
- for(auto it=P.begin();it!=P.end();it++){
- cout<<*it<<endl;
- }
在这里我们需要注意终止条件为 it!=P.end(),原因是当it为P.end()时,此时指向的地址为最后一个元素的下一位,自然需要终止。
我们同样可以用while循环来写,如何写与for循环大同小异,在此略去。
值得一提的是,我们还可以用智能指针来遍历集合,这里是两个例子:
(后面有空我会学习下智能指针,可能会单独开个文章讲讲,又是一个坑)
- set<pair<int, int>>P;
- P.insert(make_pair(2, 3));
- P.insert(make_pair(5, 2));
- for (pair<int, int> p : P) {
- cout << p.first << " " << p.second << endl;
- }
- set<string>P{"LHP", "YYT"};
- P.insert("XXX");
- for (string p : P) {
- cout << p << endl;
- }
与正序遍历类似,stl中自带逆序遍历的函数
类似的,rbegin()代表逆序遍历的第一个元素的迭代器,rend()代表逆序遍历最后一个元素下一个地址的迭代器
注意:在定义迭代器时候相应的,我们应该使用 ::reverse_iterator 而非 ::iterator 以代表反向迭代器
- set<int> P{1, 2, 3, 4, 5};
- set<int>::reverse_iterator it;
- for (it = P.rbegin(); it != P.rend(); it++)
- cout << *it << " ";
- // 输出分别为 5 4 3 2 1
简单易懂的用法,括号内填入声明数据类型的值便好
例子如下:
- set<string>P;
- P.insert("LHP");
- set<int>L;
- L.insert(666);
insert()还可以同时插入多个元素,例子见下(我觉得作用也就节省代码量吧)
- set<string>P;
- P.insert({"LHP","YYT"});
- set<int>L;
- L.insert({666,999});
你若是跟STL中的pair同时使用,则需要用到make_pair()插入
- set<pair<int,int>>P;
- P.insert(make_pair(2,3));
与insert一样同样具有插入元素的功能,但不一样的是,emplace()传入的是构造函数的对应参数而不是元素本身,这样说可能有点不明白,我们用实例去理解:
- struct Node {
- int score;
- string Name;
- Node(int inscore, string inName): score(inscore), Name(inName) {}
- bool operator<(const Node b) const {
- return this->score < b.score;
- }
- };
- set<Node>P;
- P.emplace(100, "LHP");
这里我们重载了比较算子,在这里我们先略去不提。
我们留意到,emplace内部会帮我们调用结构体构造函数,我们无需自己构造,可以节省创建实例的步骤,因此在工程中emplace往往会大量使用。
emplace()函数返回一个pair,第一个参数为set迭代器,代表插入地址,第二个参数为一个bool值,代表是否成功插入
删除只有erase()一个函数,但是其有三种用法
括号内填入删除元素
例子:
- set<string>P;
- P.insert("666");
- P.erase("666");
返回一个整数,代表删除元素的个数
括号内填set的迭代器
- set<string>P;
- P.insert("666");
- set<string> ::iterator it = P.begin();
- P.erase(it);
返回的迭代器为删除元素的后一个位置
- set<string>P{"11", "22", "33"};
- set<string> ::iterator it1 = P.begin(), it2 = P.end();
- P.erase(it1, it2);
注意:这里第二个参数传入的代表删除末尾元素的下一位,it2这个位置是不被删除的!
P.erase()
或者很无聊地利用上面③中的代码一样可以达到清空set的目的
set中的查询函数,传入我们要查询的value,返回一个迭代器。
如果找到该元素,则返回该元素的地址的迭代器,如果没找到,则返回end()值
- P1.find("LHP");
- P2.find(666);
- P3.find(make_pair(2,3));
返回对应元素的个数,实际上由于集合内元素的特异性,返回的非0即1(1表示存在,0表示无)
我是觉得没有什么卵用,不如用find()应用场景更广
- P1.count("LHP");
- P2.count(666);
- P3.count(make_pair(2,3));
括号内填入元素
lower_bound()返回第一个大于等于val的迭代器
upper_bound()返回第一个严格大于val的迭代器
注意:这里很容易弄混,请记牢
- set<int> P{1, 2, 3, 4, 5};
- cout << *P.lower_bound(2) << endl;
- cout << *P.upper_bound(2) << endl;
- // 输出分别为 2 3
另外一种函数叫做equal_range()可以返回一个pair,pair的第一个为lower_bound()迭代器,第二个则为upper_bound()的迭代器
例子如下:
- set<int> P{1, 2, 3, 4, 5};
- auto it = P.equal_range(2);
- cout << *it.first << " " << *it.second << endl;
- // 输出分别为 2 3
这里图省事用了auto
第一个返回的是lower_bound(),第二个返回的是upper_bound()
访问这个pair中的元素注意是迭代器,访问迭代器内容还要用指针的“ * ”
- P.empty() 返回是否为空,是则为1,不是则为0
- P.size() 返回集合的大小(几个元素
花了两个晚上去写这个小总结,参考了许多文档,感谢这些前辈。
果然总结是有许多好处的,对于set原来一知半解的我在写完博客后完全透析了,果然输出才是最好的学习方法。
关于set的暂时就告一段落了,其实还有类似emplace_hint()的函数,但在这里不加介绍,另外实际上还有 mulset 这一STL容器,可以看看在未来进行文章再总结用法。
感谢你看到这里,希望这篇文章对你的学习工作有所帮助,如果有任何意见,麻烦写到评论区,我会好好采纳并修改。
参考资料:
详解c++---set的介绍_c++ set_叶超凡的博客-CSDN博客
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。