C++STL set/multiset容器
1、set/multiset容器简介
- set元素的特性是所有元素都会根据元素的键值自动排序。set的元素不像map可以同时拥有实值和键值,set的元素既是实值也是键值。set不允许两个元素有相同的键值。不能通过set的迭代器改变set元素的值,因为set的元素值就是键值,关系到set元素的排序规则,如果任意改变set元素值,会严重破坏set组织。
- set的迭代器是一种const_iterator(常量迭代器)。set拥有和list某些相同的性质,当对容器中的元素进行插入或删除操作时,除了被删除的那个元素不会造成其他元素的迭代器失效。
- multiset特性及用法和set完全相同,唯一的差别在于它允许键值重复。 set和multiset的底层实现是红黑树(一种平衡二叉树)。
2、API
/*******************************set构造函数******************************/
set<T> st;//set默认构造函数
multiset<T> mst;//multiset默认构造函数
set(const set &st);//拷贝构造函数
/************************赋值操作*************************************/
set& operator=(cosnt set& st);重载=运算符
swap(st);//交换两个集合容器
/****************************大小操作*******************************/
size();//返回容器中元素的数目
empty();//判断容器是否为空
/*************************插入和删除操作***************************/
insert(elem);//在容器中插入元素
clear();清除所有元素
erase(pos);//删除pos迭代器所指向的元素,返回下一个元素的迭代器
erase(beg,end);//删除区间[beg,end)的所有元素,返回下一个元素的迭代器
erase(elem);//删除容器中值为elem的元素
/**********************查找操作******************************/
find(key);//查找键key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end()
cout(key);//返回键key的元素个数
lower_bound(keyElem);//返回第一个key>=keyElem元素的迭代器
uppper_bound(keyElem);//返回第一个key>keyElem元素的迭代器
equal_range(keyElem);//返回容器中key与keyElem相等的上下限的两个
3、使用
insert、erase
- set会对插入的元素按照指定的排序规则进行自动排序,对于基本数据类型,默认按照从小到大排序。
- set不允许插入相同的键值,insert()函数返回值为对组pair<iterator,bool>,即返回插入位置的迭代器和插入的结果,如果插入了相同的键值,则根据返回值可知插入失败。
void test()
{
set<int> s;
s.insert(20);
s.insert(40);
s.insert(30);
s.insert(40);
s.insert(10);
for_each(s.begin(),s.end(),[](int val){
cout<<val<<" ";
});//10、20、30、40
//set容器提供的是只读迭代器const_iterator
//用户不可以修改set容器的元素
set<int>::const_iterator it=s.begin();
//*it=100;//error
cout<<"size="<<s.size()<<endl;//4
//删除起始位置的元素
s.erase(s.begin());
for_each(s.begin(),s.end(),[](int val){
cout<<val<<" ";
});//20 30 40
//根据元素删除
s.erase(40);
for_each(s.begin(),s.end(),[](int val){
cout<<val<<" ";
});//20 30
//count(key)查找键key的元素个数
//set容器的键值是不重复的,那么count(key)只能是1或0
cout << s.count(40) << endl;//0
}
对组(pair)
这里对对组进行简要介绍。对组将一对值合成一个值,这一对值可以具有不同的数据类型,两个值可以分别用pair的两个公有属性first和second访问。
类模板:template<class T1,class T2>struct pair
//第一种创建对组的方法
pair<string,int> pair1(string("name"),20);
cout<<pair1.first<<endl;//访问pair第一个值
cout<<pair1.second<<endl;//访问pair第二个值
//第二种
pair<string,int> pair2=make_pair("name",20);
cout<<pair2.first<<endl;//访问pair第一个值
cout<<pair2.second<<endl;//访问pair第二个值
//第三种=赋值
pair<string,int> pair3=pair2;
cout<<pair3.first<<endl;//访问pair第一个值
cout<<pair3.second<<endl;//访问pair第二个值
void test()
{
//10086--移动 10010--联通
//定义对组方式1:
pair<int,string> pair1(10086,"移动");
cout<<"编号:"<<pair1.first<<",名称:"<<pair1.second<<endl;
//定义对组方式2(推荐):
pair<int,string> pair2=make_pair(10010,"联通");
cout<<"编号:"<<pair2.first<<",名称:"<<pair2.second<<endl;
}
lower_bound、upper_bound
void test()
{
set<int> s;
s.insert(10);
s.insert(20);
s.insert(30);
s.insert(40);
s.insert(50);
for_each(s.begin(),s.end(),[](int val){
cout<<val<<" ";
});//10、20、30、40、50
//下限:lower_bound(keyElem);//返回第一个key>=keyElem元素的迭代器
set<int>::const_iterator lower_ret;
lower_ret =s.lower_bound(30);
if(lower_ret==s.end()){
cout<<"没有找到30的下限!"<<endl;
}
else{
cout<<"找到30的下限:"<<*lower_ret<<endl;
}
//upper_bound(keyElem);//返回第一个key>keyElem元素的迭代器
set<int>::const_iterator up_ret;
up_ret=s.upper_bound(30);
if(up_ret==s.end()){
cout<<"没有找到30的上限!"<<endl;
}
else{
cout<<"找到30的上限:"<<*up_ret<<endl;
}
//equal_range(keyElem);//返回容器中与keyElem相等的key的上下限的两个迭代器
//equal_range返回的是一个对组
//first是对组中第一个值,second是队组中第二个值
pair<set<int>::const_iterator,set<int>::const_iterator> pair_ret;
pair_ret=s.equal_range(30);
if(pair_ret.first==s.end()){//下限lower_bound
cout<<"下限未找到!"<<endl;
}
else{
cout<<"下限找到:"<<*(pair_ret.first)<<endl;
}
if(pair_ret.second==s.end()){//上限upper_bound
cout<<"下限未找到!"<<endl;
}
else{
cout<<"下限找到:"<<*(pair_ret.second)<<endl;
}
}
更改set排序规则
- set容器存放基本数据类型,由于<>中要求既是一个类型,又是一个指定排序规则函数,所以只能是仿函数,普通函数不行。
#include<iostream>
#include<set>
#include<algorithm>
using namespace std;
class MyGreater {
public:
bool operator()(int val1,int val2) {//从大到小排序(容器中的排序逻辑都是真则不交换,假则交换)
return val1 > val2;
}
};
void test()
{
//默认从小到大
//改成从大到小
//set<int,排序规则> s;
set<int, MyGreater> s;
s.insert(30);
s.insert(10);
s.insert(20);
s.insert(40);
for_each(s.begin(), s.end(), [](int val) {cout << val << " "; });
}
- set存放自定义数据时有两种选择,一种是重载<运算符,一种是使用仿函数,必须从两者中选择一种,否则会定义失败。
set容器存放自定义数据时重载<运算符
#include<iostream>
#include<set>
#include<string>
#include<algorithm>
using namespace std;
class Person {
public:
string name;
int age;
Person(string n, int a) {
name = n;
age = a;
}
//重载<运算符
bool operator<(const Person& ob)const {//此处两个const必须加上
return age < ob.age;
}
};
void test()
{
//重载<指定排序规则
set<Person> s;
s.insert(Person("小明",16));
s.insert(Person("小红", 18));
s.insert(Person("小李", 15));
s.insert(Person("小天", 16));
for_each(s.begin(), s.end(), [](Person val) {
cout << val.name << " "<<val.age<<endl;
});
}
set存放自定义数据时指定排序规则(仿函数)
#include<iostream>
#include<set>
#include<string>
#include<algorithm>
using namespace std;
class Person {
public:
string name;
int age;
Person(string n, int a) {
name = n;
age = a;
}
};
class MyGreater {
public:
bool operator()(Person val1, Person val2) {
return val1.age < val2.age;
}
};
void test()
{
//使用仿函数指定排序规则
set<Person,MyGreater> s;
s.insert(Person("小明",16));
s.insert(Person("小红", 18));
s.insert(Person("小李", 15));
s.insert(Person("小天", 16));
for_each(s.begin(), s.end(), [](Person val) {
cout << val.name << " "<<val.age<<endl;
});
}