文章目录
关键特性
- 唯一性 :Set容器内的元素都是唯一的 ,每个元素都是不同的
- 有序性 :Set容器内的元素总是排序的(C++中默认升序),向Set中添加元素,将自动插入到正确的位置中,不需要手动排序
- 查找/插入快速 :因为Set容器的元素是排序的,所以在Set中查找和插入元素都很快
定义及初始化
cpp
#include <set>
set<Type> s;
set<int> s = {1,2,3,4,5};
vector<int> a = {1,2,3,4,5};
set<int> s(a.begin(),a.end());
set<Type> s(s1); //定义一个set容器,并用容器s1来初始化
set<Type> s(b, e); //b和e分别为迭代器的开始和结束的标记
set<Type> s(s1.begin(), s1.begin()+3); //用容器s1的第0个到第2个值初始化s
set<Type> s(a, a + 5); //将a数组的元素初始化vec向量
set<Type> s(&a[1], &a[4]); //将a[1]~a[4]范围内的元素作为s的初始值
一些基本操作
cpp
s.begin(); //返回指向第一个元素的迭代器
s.end(); //返回指向最后一个元素的迭代器
s.clear(); //清除所有元素
s.count(); //返回某个值元素的个数
s.empty(); //如果集合为空,返回true,否则返回false
s.equal_range(); //返回集合中与给定值相等的上下限的两个迭代器
s.erase(); //删除集合中的元素
s.find(k); //返回一个指向被查找到元素的迭代器
s.insert(); //在集合中插入元素
s.lower_bound(k); //返回一个迭代器,指向键值大于等于k的第一个元素
s.upper_bound(k); //返回一个迭代器,指向键值大于k的第一个元素
s.max_size(); //返回集合能容纳的元素的最大限值
s.rbegin(); //返回指向集合中最后一个元素的反向迭代器
s.rend(); //返回指向集合中第一个元素的反向迭代器
s.size(); //集合中元素的数目
查找
find(x)
方法寻找带有特定键的元素,返回的是迭代器。
cpp
set<int> s = {1,2,3,4,5};
if(s.find(3)!=s.end())//若存在,返回一个迭代器,指向键值;若不存在,返回一个迭代器,指向s.end()。
cout<<*s.find(3)<<endl;
else
cout<<"NOT FOUND"<<endl;
count(x)
方法返回的是set
中元素x
的个数。由于个数只能是0或1,所以当返回值非0时表示元素在集合中,反之不在。
cpp
set<int> s = {1,2,3,4,5};
if(s.count(3) > 0)
cout << s.count(3) << endl;
else
cout<<"NOT FOUND"<<endl;
插入
cpp
//插入一个元素
set<int> s;
s.insert(10);
//插入多个元素
vector<int> array{1, 2, 3};
int a[] = {1,2,3};
set<int> s;
s.insert(array.begin(), array.end());
s.insert(a,a+3);
//使用emplace函数插入元素
set<int> s;
s.emplace(10);
删除
语法格式
cpp
set_name.erase(element);//删除 set 容器中值为 val 的元素
name.erase(iterator position);//删除 position 迭代器指向的元素
name.erase(iterator start, iterator end);//删除 [start,end) 区间内的所有元素
示例
cpp
set<int> myset={1,2,3,4,5};
myset.erase(30);
myset.erase(myset.find(3));
myset.erase(myset.begin(),myset.end())
Reference:
https://vimsky.com/examples/usage/unordered_set-erase-function-in-c-stl.html
https://www.cainiaojc.com/cpp/cpp-set-erase-function.html
https://c.biancheng.net/view/7198.html
https://blog.csdn.net/chenyijun/article/details/119065095
清空
cpp
myset.clear();
遍历
迭代器遍历
cpp
set<int> myset={1,2,3,4,5};
for(auto it = mySet.begin(); it != mySet.end(); it++)
{
cout<<*it<<" ";
}
cout<<endl;
for循环新用法
cpp
set<int> myset={1,2,3,4,5};
for(auto i : myset){
cout<<i<<endl;
}
lower_bound()、upper_bound()
lower_bound(key_value) :返回第一个大于等于key_value的定位器
upper_bound(key_value):返回第一个大于key_value的定位器
cpp
set<int> s={1,2,3,4,5};
cout<<*s.lower_bound(1)<<" ";
cout<<*s.lower_bound(2)<<" ";
cout<<*s.upper_bound(3)<<" ";
//输出:1 2 4
set与unordered_set的区别
set与unordered_set一样,都是关联式容器,和 map 容器不同,使用 set 容器存储的各个键值对,要求键 key 和值 value 必须相等。
当使用 set 容器存储键值对时,只需要为其提供各键值对中的 value 值(也就是 key 的值)即可。
使用 set 容器存储的各个元素的值必须各不相同。
从语法上讲 set 容器并没有强制对存储元素的类型做 const 修饰,即 set 容器中存储的元素的值是可以修改的。但是,C++ 标准为了防止用户修改容器中元素的值,对所有可能会实现此操作的行为做了限制,使得在正常情况下,用户是无法做到修改 set 容器中元素的值的。
主要区别:
set
- 定义于头文件
- 底层实现通常是平衡二叉树
- 元素自动排序,这为查找元素提供了良好性能,但同时也造成了一个重要限制:不能直接改变元素值,因为这会打乱原本正确的顺序
- 查找函数具有对数复杂度
- 要改变元素的值,必须先删除该元素,再插入新元素
unordered_set
- 定义于<unordered_set>头文件
- 底层实现通常是hash-table
- 元素是无序的
- 插入、删除、查找元素的时间复杂度是常量的(排除偶尔的rehashing导致的线性复杂度)
总结
综上,以下情况使用set:
- 需要排序的数据
- 需要通过前序、后序等方式遍历元素或者查找前继后继元素
- 想要使用binary_search(), lower_bound() and upper_bound()等需要在有序元素上使用的方法
- 其他平衡二叉树具有而hash表没有的优点
在以下情况使用unordered_set:
- 仅需要保存互异的元素而不需要排序
- 只需要获取单个元素而不需要遍历
两者的区别参考:
https://zhuanlan.zhihu.com/p/439197313
https://blog.csdn.net/bryant_zhang/article/details/111600209
https://zhuanlan.zhihu.com/p/131009604
reference:
https://blog.csdn.net/weixin_44668898/article/details/102089892
还可以参考: