set称为集合,是一个内部自动有序且不含重复元素的容器。他只有key值,不是键值对类型的。底层实现是依靠红黑树实现。插入和删除元素时间复杂度为O(logN)。set最重要的作用就是自动去重和按照升序排序。set中的元素唯一,如果需要处理不唯一的情况,需要使用multiset。unordered_set可以用来处理只去重但不排序的要求,速度比set要快许多。可以对比map。
1.2、定义
#include
set<类型>s;//类型可以是:int double,char,结构体,set,vector等等。set(集合)的特点就是可以忽略set中元素类型的影响,可以理解为纯粹的容器。
sets[100];//set数组,s[0]-s[99]的每一个元素都是一个set容器。
int arry[] = {1,2,3,4,5};
sets1(arry,arry+sizeof(arry) / sizeof(arry));//使用arry数组初始化s1。
1.3、set容器元素的访问
set容器的访问只能通过迭代器。
set<类型>::iterator it;//这样就得到了set的迭代器it,可以通过*it来访问set的元素。
vector和string之外的STL容器都不支持*(it+i)的访问方式,因此访问set内的元素只能按如下方式。
sets;
/*省略set赋值的部分*/
set::iterator it;
it=s.begin();
while(it!=s.end())
{
cout<<*it++<<' ';
}
//或者
for(auto &e : s)
{
cout<< e <<' ' ;
}
1.4、set的一些函数
插入元素:insert函数。
sets;
s.insert(1);//插入元素1。
查询元素:find函数。返回值是元素的迭代器。
set::iterator it=s.find(1);//查找值为1的元素,返回的是1这个元素的迭代器。
printf("%d",*it);
删除元素:erase函数。erase函数有多种用法。
用法1:结合find,删除单个元素。
set::iterator it=s.find(1);
s.erase(it);//it为元素值为1的迭代器。
用法2:
s.erase(1);//直接删除值为1的元素。
用法3:删除一个区间的元素。
s.erase(first,last);//删除[first,last)内的所有元素其中first为其实元素的迭代器,last为删除区间的末尾迭代器的下一个。
其他函数:
//逆向打印s1的元素的值。(即从大到小打印)
for (auto it=s1.rbegin(); it!=s1.rend();++it)
{
cout << *it << ' ';
}
//计算值为2的元素出现了几次。
cout << s1.count(2) << endl;
unordered_set和set基本相同,也是不允许有重复元素。底层实现是哈希表存储结构。只是set内的元素是有序的,set自动排序。unordered_set是无序的,按插入元素先后顺序排列。且unordered_set没有rbegin和rend函数。(由于unordered_set比较简单,这里不对此做过多介绍。)
#include
unordered_sets1;
multiset是
#include //头文件
multisetm;
m.insert(2);m.insert(1); m.insert(3); m.insert(2);
for (auto &e : m)
{
cout << e << " ";
}
cout << endl;
输出结果:1 2 2 3
multiset和set用法一样,也可以放入自定义的类型。只不过,放入自定义的类型需要说明一下如何比较类型的大小。比如:
struct rec
{
int x, y;
};
struct cmp
{
bool operator()(const rec&a, const rec&b)
{
//x为第一关键字,y为第二关键字进行比较。
return a.x < b.x || a.x == b.x && a.y < b.y;
}
};
multisetm;//m的每一个元素都是rec这个结构体,如何比较m元素之间的大小关系呢,通过cmp来比较。
multiset的函数和set相同,此处不做说明,如需要可自行查找。
map是由一对键值对组成(key----value),map是有序的,里面的元素排序是根据key的大小按升序排列,底层实现和set一样都是红黑树。如果是自定义类型无法比较时,需要用户自己显式传递比较规则。头文件:#include
unordered_map是无序的哈希表。STL容器中所有的无序容器底层实现都是采用哈希表的存储结构。更准确的说是用“链地址法”解决哈希冲突。头文件:#include
Map和Set的区别
map和set都是C++的关联容器,其底层实现都是红黑树(RB-Tree) 。于map和
set所开放的各种操作接口,RB-ree 也都提供了,所以几乎所有的map和set的操作
行为,都只是转调RB-tree的操作行为。
map和set区别在于:
● map中的元素是key-value (关键字-值)对:关键字起到索引的作用,值则表示与
索引相关联的数据; Set与之相对就是关键字的简单集合, set中每个元索只包含一
个关键字。
● set的迭代器是const的,不允许修改元素的值; map允许修改value,但不允许修改
key。其原因是因为map和set是根据关键字排序来保证其有序性的,如果允许修改
key的话,那么首先需要删除该键,然后调节平衡,再插入修改后的键值,调节平
衡,如此-来,严重破坏了map和set的结构,导致iterator失效, 不知道应该指向
改变前的位置,还是指向改变后的位置。所以STL中将set的迭代器设置成const,
不允许修改迭代器的值;而map的迭代器则不允许修改key值,允许修改value值。
● map支持下标操作,set不支持下标操作。map可以用key做下标,map的下标运算
符[ ]将关键码作为下标去执行查找,如果关键码不存在,则插入一个具有该关键码
和mapped_ _type类型默认值的元素至map中,因此下标运算符[ ]在map应用中需要
慎用,const_ map不能用,只希望确定某一个关键值是否存 在而不希望插入元素时
也不应该使用,mapped_ type类型没有默认值也不应该使用。如果find能解决需
要,尽可能用find。