说到集合,我们在数学中就学过集合的概念。集合中有两种特性:互异性(集合中的元素各不相同)和无序性(元素所在位置无顺序关系)。
在C++中,封装了STL类,相比传统集合概念,有一定区别。关于集合包括:set、multiset、unordered_set、unordered_multiset。下面对这四种集合类做个简要介绍:
set:集合内元素是有序的,每个元素唯一。
multiset:集合内元素是有序的,每个元素可以不唯一,可以重复。
unordered_set:集合内元素是无序的,每个元素唯一。
unordered_multiset:集合内元素是无序的,每个元素可以不唯一,可以重复。
总而言之,set和multiset类用于存储一组有序的元素,查找的时间复杂度为O(logn),unordered_set和unordered_multiset类中存储的元素是无序的,因此在集合中查找和插入元素的时间是一致(固定)的。
注:使用set
和multiset
类时,需要定义头文件:
#include
如果需要对程序频繁查找操作的话,set
和multiset
类具有一定的优势,这两类是经过排序的,有序的,所以查找速度会快于其他类。
具体来讲:在向集合中插入元素时通过find()
函数来找到合适的位置进行排序。因此,在新增(插入)元素时,无疑会增加额外的开销,但find()内部实现使用的是二叉树结构。该结构用于查找的时间复杂度往往在O(logn)左右。
但是也存在一定的缺陷:set
和multiset
类不如之前讲的vector
类,vector可以使用其他元素替换给定位置的元素,而set
和multiset
类将把新元素同二叉树中的其他元素进行比较,进而将其放在其他位置。
总而言之,set
和multiset
类和vector
相比:
优点:set
和multiset
类内部时类似二叉树结构,查找速度快;
缺点:在增加元素时,会增加一点额外开销;不能使用其他元素直接替换给定位置的元素。
set
和multiset
类和之前一样,都是模板类,必须要先实例化:
(1) 实例化一个整型set或multiset。
set <int> setNums;
multiset <int> msetNums;
(2) 声明一个含有Tina对象的set或multiset。
set <Tina> setNums;
multiset <Tina> msetNums;
(3) 使用复制,实例化set或multiset。
set <int> setNums1(setNums);
multiset <int> msetNums1(msetNums);
这三种方式都没有规定顺序,默认升序。如果想规定集合元素顺序,可以提前声明定义。
# 升序排序
set<int, less<int>>setNums;
# 降序排序
set<int, greater<int>>setNums;//greater<>是个函数,降序,所以要加这个头文件#include
集合类也有自己的成员函数,包括插入、查找、删除等。成员函数,能够解决很多问题,使代码更加简洁。
set
和multiset
类可以使用insert()
函数,在集合中插入值。
#include
#include
using namespace std;
template <typename T>
void DisplayContents(const T& Input)
{
for(auto iElement = Input.cbegin();iElement != Input.cend(); ++iElement)
cout<<*iElement<<" ";
cout<<endl;
}
int main()
{
set <int> setIntegers;
multiset <int> msetIntegers;
setIntegers.insert(60);
setIntegers.insert(-1);
setIntegers.insert(300);
cout<<"显示内容到屏幕:"<<endl;
DisplayContents(setIntegers);
msetIntegers.insert(setIntegers.begin(), setIntegers.end());
msetIntegers.insert(300);
cout<<"再插入一个元素后,显示内容到屏幕:"<<endl;
DisplayContents(msetIntegers);
cout<<"300的数量是:"<<msetIntegers.count(300)<<endl;
return 0;
}
在set
和multiset
类中,可以使用成员函数find()
来查找相应的元素。但是,multiset 可能包含多个相同的元素。因此对于multiset,find()
函数查找第一个与给定值匹配的元素。
#include
#include
using namespace std;
int main()
{
set<int> setNums;
//插入元素
setNums.insert(50);
setNums.insert(-48);
setNums.insert(6);
setNums.insert(160);
//显示集合元素
for (auto iElement=setNums.cbegin(); iElement != setNums.cend(); ++iElement)
cout<<*iElement<<endl;
//查找集合元素-1
auto iElementFound = setNums.find(-1);
if(iElementFound != setNums.end())
cout<<"Element "<<*iElementFound<<" found!"<<endl;
else
cout<<"Element -1 not found in setNums!"<<endl;
//查找集合元素6
auto anotherFind = setNums.find(6);
if(anotherFind != setNums.end())
cout<<"Element "<<*anotherFind<<" found!"<<endl;
else
cout<<"Element 6 not found in setNums!"<<endl;
return 0;
}
在set
和multiset
类中,和其他模板类一样,可以使用erase()
函数删除元素。
#include
#include
using namespace std;
template <typename T>
void DisplayContents(const T& Input)
{
for(auto iElement = Input.cbegin();iElement != Input.cend(); ++iElement)
cout<<*iElement<<" ";
cout<<endl;
}
int main()
{
multiset <int, greater<int>> msetNums;
msetNums.insert(46);
msetNums.insert(78);
msetNums.insert(-100);
msetNums.insert(-100);
msetNums.insert(8);
cout<<"msetNums 包含 "<<msetNums.size()<<" 个元素"<<endl;
cout<<"降序显示mseNums全部元素:"<<endl;
DisplayContents(msetNums);
msetNums.erase(-100);
cout<<"删除-100后,显示mseNums全部元素:"<<endl;
DisplayContents(msetNums);
return 0;
}
(1) set
和multiset
容器针对频繁查找的情形进行了优化;
(2) multiset
可存储多个值相同的元素,而set
只能存储不同的值。
(3) 使用count()
可获得元素包含特点值的个数;
(4) 使用size()
可获得集合包含的元素个数。
(5) 在需要频繁插入而很少查找的情形下,不要使用set
和multiset
; 在这种情况下,使用vector和list更合适。
最后,长话短说,大家看完就好好动手实践一下,切记不能三分钟热度、三天打鱼,两天晒网。大家也可以自己尝试写写博客,来记录大家平时学习的进度,可以和网上众多学者一起交流、探讨,我也会及时更新,来督促自己学习进度。一开始提及的博主【AI菌】,个人已关注,并订阅了相关专栏(对我有帮助的),希望大家觉得不错的可以点赞、关注、收藏。