STL常用容器—set容器
参考博文:STL常用容器——set容器的使用
1. set容器相关概念
set容器特点:
- 所有元素插入时候会被自动排序
- set容器不允许插入重复值
- 出入数据 只能用insert
set容器本质:
set/multiset属于关联式容器,底层结构是用二叉树实现
2. 初始化容器
定义与初始化
默认构造:
set<int> s1;
构造容器并初始化:
set<int> s2{1,2,3,5,4};
拷贝构造:
set<int> s3(s2);
//等同于赋值
set<int> s3 = s2;
插入数据
set容器插入数据只能使用insert
set<int> s2{1,2,3,5,4};
s2.insert(15); //s2容器中插入数据15
s2.insert(10); //s2容器中插入数据10
s2.insert(15); //s2容器中插入数据15
show_set(s2);
若插入已存在的数据,插入失败但不报错,因为set容器数据不能重复
输出结果:
1 2 3 5 4 5 10 15
打印输出
注: 打印输出容器函数,后续打印没有特别说明均使用的是该函数
void show_set(set<int> &s)
{
for(set<int>::iterator it = s.begin(); it != s.end();it++)
cout << *it << " ";
cout << endl;
}
3. set容器插入和删除
方法 | 功能 |
---|---|
☆ insert( elem ) | 在容器中插入元素,常用 |
clear( ) | 清空容器(删除所有元素) |
erase( pos ) | 删除pos迭代器所指的元素,返回下一个元素的迭代器 |
erase(beg, end) | 删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器 |
☆ erase(elem) | 删除容器中值为elem的元素 |
void test03()
{
set<int> s1{2,5,3,8,0,3,6}; //构造容器并初始化
//容器实际排序 0 2 3 5 6 8
//删除某个元素
s1.erase(100); //若该元素不存在,则容器不变
//删除某个迭代位置 删除第一个
s1.erase(s1.begin()); // 2 3 5 6 8
//删除最后一个
s1.erase(--s1.end());
show_set(s1); // 2 3 5 6
//删除某个迭代区间
s1.erase(++s1.begin(), --s1.end());
show_set(s1); // 2 6
s1.clear(); //清空容器
}
4. set容器大小和交换
方法 | 功能 |
---|---|
size(); | 返回容器中元素的数目 |
empty( ); | 判断容器是否为空 |
swap( st ); | 交换两个集合容器 |
void test04()
{
set<int> s1{10,20,45,30}; //默认构造
set<int> s2{1,2,3,5,4}; //构造容器并初始化
//判断容器是否为空
if(!s1.empty()){
//若不为空 则输出容器的大小
cout << "s1.size= " << s1.size() << endl;
cout << "s1: ";
show_set(s1); //打印容器
}
if(!s2.empty()){
cout << "s2.size= " << s2.size() << endl;
cout << "s2: ";
show_set(s2);
}
//交换两个容器 并输出交换后的结果
cout << "swap(s1,s2)" << endl;
cout << "s1: ";
show_set(s1);
cout << "s2: ";
show_set(s2);
}
输出结果:
s1.size= 4
s1: 10 20 30 45
s2.size= 5
s2: 1 2 3 4 5
swap(s1,s2)
s1: 10 20 30 45
s2: 1 2 3 4 5
注: set容器不支持resize方法。
5. set容器的查找和统计
方法 | 功能 |
---|---|
find(key); | 查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end(),常用 判断元素是否出现等 |
count(key); | 统计key的元素个数 |
注:
(1)对于set容器而言,元素的值是不能重复的,因此count返回的值为1或0,key元素存在则返回1,不存在则返回0。
(2)find函数返回的是迭代器
void test()
{
set<int> s1{2,5,3,8,0,3,6}; //构造容器并初始化
//set容器实际排序 0 2 3 5 6 8
//查找
set<int>::iterator pos = s1.find(3);
if(pos != s1.end())
cout << "找到该元素:" << *pos << endl;
else
cout << "未找到该元素" << endl;
//统计个数
int num = s1.count(3);
if(num == 1)
cout << "存在该元素 个数为1" << endl;
else
cout << "不存在该元素 " << endl;
}
输出结果:
找到该元素:3
存在该元素 个数为1
6. set、multiset、unordered_set三者的区别
集合 | 是否有序 | 数值知否可重复 | 底层实现 |
---|---|---|---|
std::set | 有序 | 不可重复 | 红黑树 |
std::multiset | 有序 | 可重复 | 红黑树 |
std::unordered_set | 无序 | 不可重复 | 哈希表 |
(1)在哈希表数据结构算法中,若输出的结果是去重的, 同时可以不考虑输出结果的顺序,则优先使用unordered_set
容器,底层为哈希表,相对数的查找效率更高
(2)set和multiset 在头文件 #include <set>
中,而unordered_set 在头文件 #include <unordered_set>
中
set容器插入数据
set.insert函数原型:
_Pairib insert(value_type&& _Val)
_Pairib定义:
using _Pairib = pair<iterator, bool>
本质上是pair,称为对组,即成对出现的一组数据,有两个数据成对出现,第一个数据是迭代器,第二个数据为bool类型的数据,定义一个对组用来接收insert的返回值
pair<set<int>::iterator, bool> ret;
获取set容器的insert插入结果
void test06()
{
set<int> s1{2,5};
pair<set<int>::iterator, bool> ret = s1.insert(3);
if(ret.second == true) //通过ret.second 读取对组里面的第二个值
cout << "第一次插入成功"<< endl;
else
cout << "第一次插入失败"<< endl;
ret = s1.insert(3);
if(ret.second == true)
cout << "第二次插入成功"<< endl;
else
cout << "第二次插入失败"<< endl;
}
输出结果:
第一次插入成功
第二次插入失败
multiset容器插入数据
ms.insert函数原型:
iterator insert(value_type&& _Val)
multiset容器insert插入函数返回的是一个迭代器
multiset<int> ms{2,5};
ms.insert(10);
ms.insert(10);
ms.insert(10);
for(multiset<int>::iterator it=ms.begin(); it != ms.end(); it++)
cout << *it << " ";
cout << endl;
输出结果:
2 5 10 10 10
因此如果不允许插入重复数据可以利用set,如果需要插入重复数据利用multiset
7. pair对组的创建
如果一个函数想要返回两个数据,可以考虑使用对组返回数据,两个数据分别用pair的两个公有函数 first 和 second 访问。
对组的创建:
- pair(); 默认构造函数
- pair<type,type> p( value1,value2); 直接使用 2 个元素初始化成 pair 对象
- pair(const pair<U,V>& pr) 拷贝(复制)构造函数
- pair<type,type> p = make_pair(value1,value2);
有参构造:
pair<string, int> stu1("zhangsan", 22);
利用make_pair函数:
pair<string, int> stu2 = make_pair("lisi", 20);
数据赋值与读取:
void test07()
{
pair<string, int> stu; //默认构造函数
pair<string, int> stu1("zhangsan", 22); //有参构造
pair<string, int> stu2 = make_pair("lisi", 20); //使用make_pair函数
pair<string, int> stu3(stu2); //拷贝(复制)构造函数
stu.first = "lihua";
stu.second = 18; //对stu对组数据赋值
stu3.first = "wangwu"; //修改stu3第一个数据,第二个数据拷贝的stu2
//读取对组数据
cout << "stu name= " << stu.first << "\tage= " << stu.second << endl;
cout << "stu1 name= " << stu1.first << "\tage= " << stu1.second << endl;
cout << "stu2 name= " << stu2.first << "\t\tage= " << stu2.second << endl;
cout << "stu3 name= " << stu3.first << "\tage= " << stu3.second << endl;
}
输出结果:
8. set容器的排序
set容器默认排序规则为从小到大,但可通过仿函数,改变排序规则。在这里仿函数不过多讲解,只进行应用,仿函数相当于重载了函数调用运算符()。
set容器存放内置数据类型
一旦对set容器插入数据后,容器内顺序已经固定,因此要改变容器的排序顺序,应**先设定排序顺序,再插入数据**。在设置排序规则时,需要使用仿函数,因此先定义从大到小的排序仿函数。定义仿函数
//set容器的排序
//从大到小的排序仿函数
class Myset
{
public:
bool operator()(int v1, int v2) //第一个()表重载的符号,第二个()是函数参数列表的括号
{
return v1>v2;
}
};
定义从大到小排序的s2容器
//指定排序规则为从大到小 对s2容器起作用
set<int, Myset> s2{2,5,3,8,0,3,6}; //仿函数本质是个类型
迭代输出,注意s2的类型为set<int, Myset>
,因此s2的迭代器类型也应该为set<int, Myset>
//遍历s2容器
//s2 容器类型为set<int, Myset>, 所以迭代器类型也为set<int, Myset>
for(set<int, Myset>::iterator it = s2.begin(); it != s2.end();it++)
cout << *it << " ";
cout << endl;
完整测试代码如下:
//set容器的排序
//从大到小的排序仿函数
class Myset
{
public:
bool operator()(int v1, int v2) //第一个()表重载的符号,第二个()是函数参数列表的括号
{
return v1>v2;
}
};
void test()
{
set<int> s1{2,5,3,8,0,3,6}; //构造容器并初始化
//set容器实际排序 0 2 3 5 6 8
cout << "---------原s1容器为: ----------" << endl;
show_set(s1);
//现在s1已经确定了排序规则,无法再进行更改
//因此要在容器插入数据之前就设置排序规则
//指定排序规则为从大到小 对s2容器起作用
set<int, Myset> s2{2,5,3,8,0,3,6}; //仿函数本质是个类型
//遍历s2容器
//s2 容器类型为set<int, Myset>, 所以迭代器类型也为set<int, Myset>
cout << "---------新s2容器为: ----------" << endl;
for(set<int, Myset>::iterator it = s2.begin(); it != s2.end();it++)
cout << *it << " ";
cout << endl;
}
输出结果:
set容器存放自定义数据类型
定义自定义数据类型Student
//自定义数据类型 Student
class Student{
public:
Student(); //无参构造
Student(string name, int age, int score, char sex); //有参构造
string name;
int age;
int score;
char sex;
};
Student::Student(string name, int age, int score, char sex)
{
this->name = name;
this->age = age;
this->score = score;
this->sex = sex;
}
定义仿函数 根据学生成绩降序排序
//根据学生成绩从高到低排序的仿函数
class compareStudent
{
public:
bool operator()(const Student &stu1, const Student &stu2) //第一个()表重载的符号,第二个()是函数参数列表的括号
{
return stu1.score > stu2.score;
}
};
测试案例
void test()
{
//自定义数据 都要先指定排序规则 编译器不清楚如何排
set<Student, compareStudent> s1;
//实例化对象
Student stu1("zhangsan", 22, 80, 'm');
Student stu2("lisi", 20, 70, 'm');
Student stu3("wangwu", 21, 95, 'm');
Student stu4("chenliu", 22, 86, 'w');
//自定义数据存入set容器
s1.insert(stu1);
s1.insert(stu2);
s1.insert(stu3);
s1.insert(stu4);
//通过迭代器遍历数据
for(set<Student, compareStudent>::iterator it = s1.begin(); it != s1.end(); it++)
cout << "姓名: " << it->name << "\t年龄: " << it->age << "\t成绩: " << it->score << endl;
}
注: set容器插入自定义类型的数据,必须编写仿函数来确定排序的关键词和规则。
输出结果: