STL常用容器—set容器

本文详细介绍了STL中的set容器,包括其概念、初始化、插入与删除操作、容器大小与交换、查找和统计元素,以及set、multiset和unordered_set的区别。此外,还涉及pair对组的创建和set容器的自定义排序方法。
摘要由CSDN通过智能技术生成

参考博文: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容器插入自定义类型的数据,必须编写仿函数来确定排序的关键词和规则

输出结果:
在这里插入图片描述

  • 25
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不会编程的小江江

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值