
大家好,继上次为大家介绍完vector容器之后,今天再来为大家介绍stl另一个著名容器-set
目录
set
1.set的简单介绍
2.set的用法
1.set容器的声明
2.set的常用函数
3.set的并,交,差,对称差
后话
set
1.set的简单介绍
set的中文翻译为“集合”,实际上,c++中的set的确实现了集合的功用,与vector不同的是,set是一种关联容器。
在set容器中,元素保有其互异性,其中的每个元素都是互不相同的。(这里的互不相同是指,假如set容器中已经包含了一个数字a,那么无论之后再向set中加入多少次a,set中仍然只会有这一个元素a,不会出现很多a的情况)在某种程度上。这也意味着set具有去重功能
我们所熟知的数学“集合”不强调元素顺序,而 set 会按比较器维护元素的顺序。本文的 set<int> 使用默认比较器 std::less<int>,所以遍历时是升序;如果指定自定义比较器,顺序也会随之改变。元素是否重复同样由比较器的等价关系决定。
而且set的插入删除效率比用其他序列容器高。
之所以set容器能够自动有序,快速添加、删除,是由他的内部实现的:set容器的内部采用了一种非常高效的平衡检索二叉树:红黑树。关于红黑树,我只能说介于我现在的水平与时间,难以完全展开解释,而且红黑树在数据结构中也是比较复杂高深的,我这里就不做过多介绍,感兴趣的朋友可以自行了解~。
2.set的用法
1.set容器的声明
set容器的声明与之前我们了解过的vector类似。
下面是不同元素类型的声明示意,不是可直接编译的完整程序:每一种声明应分别使用,结构体也需要完整定义,并提供满足严格弱序的比较方式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| #include<iostream> #include<set>
using namespace std; struct node { ... }
int main() { set<int> st; set<pair<int,int>> st; set<char> st; set<node> st; }
|
2.set的常用函数
首先要介绍的就是:
st.insert( ) 在st中插入元素。
st.begin() 返回指向第一个元素的迭代器.
st.end() 返回指向最后一个元素下一个位置(注意不是最后一个元素)的迭代器.
有了这三个函数,我们就可以实现set容器的一些基本功能。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| #include<iostream> #include<set> using namespace std;
int main() { set<int> st; st.insert(4); int n; for(int i=1;i<5;i++) { cin>>n; st.insert(n); } for(auto it=st.begin();it!=st.end();it++) { cout<<*it<<" "; } return 0; }
|
上面的代码中,我们使用auto关键字定义的迭代器it,当然我们也可以用
set<int> ::iterator it=st.begin();的方式来定义一个迭代器。
st.find(value) 返回 set 中与 value 等价的元素的迭代器;未找到时返回 st.end(),不能解引用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| #include<iostream> #include<set> using namespace std;
int main() { set<int> st; st.insert(4); int n; for(int i=1;i<5;i++) { cin>>n; st.insert(n); } auto it=st.begin(); it=st.find(2); for(;it!=st.end();it++) { cout<<*it<<" "; } return 0; }
|
st.erase(it) 删除一个元素,it为需要被删除的元素的迭代器。
st.erase(value) 删除值为value的元素。
st.erase(it1,it2) it1,it2均为迭代器,删除[it1,it2)内的元素(注意前闭后开);
在刚刚代码的基础上:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| #include<iostream> #include<set> using namespace std;
int main() { set<int> st; st.insert(4); int n; for(int i=1;i<5;i++) { cin>>n; st.insert(n); } st.erase(4); for(auto it=st.begin();it!=st.end();it++) { cout<<*it<<" "; } return 0;
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| #include<iostream> #include<set> using namespace std;
int main() { set<int> st; st.insert(4); int n; for(int i=1;i<5;i++) { cin>>n; st.insert(n); } auto it=st.begin(); st.erase(it); for(auto it=st.begin();it!=st.end();it++) { cout<<*it<<" "; } return 0;
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| #include<iostream> #include<set> using namespace std;
int main() { set<int> st; st.insert(4); int n; for(int i=1;i<5;i++) { cin>>n; st.insert(n); } auto it=st.begin(); st.erase(it,st.find(3)); for(auto it=st.begin();it!=st.end();it++) { cout<<*it<<" "; } return 0; }
|
st.count(value) 判断值为value的元素是否在容器中。
st.empty() 判断是否为空,若为空返回true。
st.clear() 清空set中所有元素。
st.size() set中元素的个数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| #include<iostream> #include<set> using namespace std;
int main() { set<int> st; int n; for(int i=1;i<5;i++) { cin>>n; st.insert(n); } cout<<st.size()<<endl; if(st.empty()) cout<<"容器为空"<<endl; else cout<<"容器不为空"<<endl; if(st.count(3)) cout<<"容器内有3"<<endl; else cout<<"容器内没有3"<<endl; st.clear(); if(st.empty()) cout<<"容器为空"<<endl; else cout<<"容器不为空"<<endl; if(st.count(3)) cout<<"容器内有3"<<endl; else cout<<"容器内没有3"<<endl; return 0; }
|
对本文使用默认比较器的 set<int>:
st.lower_bound(key_value) 返回第一个大于等于 key_value 的元素的迭代器。
st.upper_bound(key_value) 返回第一个大于 key_value 的元素的迭代器。
如果不存在符合条件的元素,两者都返回 st.end(),不能解引用。使用自定义比较器时,边界也按该比较器判断,不能直接套用数值上的“大于等于”或“大于”。
这两位也有其用法,在这里我不赘述,先举一个简单的例子,在下篇文章中我会以一道题来详细说明。
1 2 3 4 5 6 7 8 9 10 11 12 13
| #include <iostream> #include <set> using namespace std; int main () { set<int> st; st.insert(3); st.insert(4); st.insert(5); cout<<*st.lower_bound(3)<<endl; cout<<*st.upper_bound(3)<<endl; return 0; }
|
3.set的并,交,差,对称差
使用以下函数均需要包含头文件#include <algorithm>
set_intersection(取集合交集)
set_union(取集合并集)
set_difference(取集合差集)
set_symmetric_difference(取集合对称差集)
并不是只有set容器可以使用这四个函数,但两个输入区间必须按算法使用的同一个比较规则排序;使用自定义比较器的 set 时,也要向算法传入匹配的比较器。输出区间不能与任一输入区间重叠。
使用方法:(四个函数使用方法相似,这里以取并集为例)
1.set_union(A.begin(),A.end(),B.begin(),B.end(),inserter(C1,C1.end()));
将 A 和 B 的元素取并集,并通过插入迭代器写入 C1。若希望 C1 恰好保存本次并集,应先保证 C1 为空。
或:前四项不变,inserter(C1,C1.end()) 改为ostream_iterator<int>(cout,” “)。其功能为直接输出其并集。
ostream_iterator<int>(cout,” “)是一个输出流迭代器,使用时需要头文件#include <iterator>
这里第一个参数是标准输出流 std::cout,第二个参数是以空字符结尾的字符串指针,例如字符串字面量 " ",表示每个元素输出后追加的分隔符。
下面来进行一个总结:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| #include <iostream> #include <algorithm> #include <set> #include <iterator> using namespace std; int main(){ set<int>A; set<int>B; set<int>C1; set<int>C2; set<int>C3; int n; for(int i=0;i<4;i++){ cin>>n; A.insert(n); } for(int i=0;i<4;i++){ cin>>n; B.insert(n); } cout<<endl; cout<<"并集:"<<endl; set_union(A.begin(),A.end(),B.begin(),B.end(),ostream_iterator<int>(cout," ")); set_intersection(A.begin(),A.end(),B.begin(),B.end(),inserter(C1,C1.end())); cout<<endl<<"交集:"<<endl; for(auto pos=C1.begin();pos!=C1.end();pos++){ cout<<*pos<<" "; } set_difference(A.begin(),A.end(),B.begin(),B.end(),inserter(C2,C2.end())); cout<<endl<<"差集:"<<endl; for(auto pos=C2.begin();pos!=C2.end();pos++){ cout<<*pos<<" "; } set_symmetric_difference(A.begin(),A.end(),B.begin(),B.end(),inserter(C3,C3.end())); cout<<endl<<"对称差集:"<<endl; for(auto pos=C3.begin();pos!=C3.end();pos++){ cout<<*pos<<" "; } return 0; }
|
输出结果为:

完
后话
写到这里,这篇文章已经将近5000字了,也是尽我所能整理了一些set容器的相关知识,当然有一些知识比如set的自定义比较函数没有进行整理,感兴趣的朋友可以自行搜索了解一下qwq~,
话说整理stl容器的篇幅感觉会越来越长,下次我准备整理map,感觉可写的内容更多呢,有点违背这个专栏浅学的初衷,hhh。
就写到这吧,如果您喜欢可以点个赞,如果能得到您的关注支持那更是感激不尽。
下次见,bye。
校订记录(2026-10-09):本页从原文迁入后,校正了比较器、查找边界、set_union 和输出迭代器的说明;声明示例补充了示意说明,并移除了删除示例中的一个不可见字符,原文日期保留。参考:C++ 标准工作草案的关联容器要求、set_union与输出流迭代器。
评论
评论
留言服务尚未连接。
正在打开留言簿……