STL常用容器—set容器

STL常用容器—set容器

  • 1. set容器相关概念
  • 2. 初始化容器
  • 3. set容器插入和删除
  • 4. set容器大小和交换
  • 5. set容器的查找和统计
  • 6. set、multiset、unordered_set三者的区别
  • 7. pair对组的创建
  • 8. 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 6s1.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;elsecout << "未找到该元素" << 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;elsecout << "第一次插入失败"<< endl;ret = s1.insert(3);if(ret.second == true)cout << "第二次插入成功"<< endl;elsecout << "第二次插入失败"<< 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 8cout << "---------原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容器插入自定义类型的数据,必须编写仿函数来确定排序的关键词和规则

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/458672.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

力扣热门100题 - 4.寻找两个正序数组的中位数

力扣热门100题 - 4.寻找两个正序数组的中位数 题目描述&#xff1a;示例&#xff1a;提示&#xff1a;解题思路&#xff1a;代码&#xff1a; 题目链接&#xff1a;4.寻找两个正序数组的中位数 题目描述&#xff1a; 给定两个大小分别为 m 和 n 的正序&#xff08;从小到大&a…

yolov8使用旋转框自己做数据集检测

主要在数据集制作&#xff0c;训练的步骤和目标检测是一样的 1.数据集标注主要使用rolabelimg工具&#xff0c;这个工具不能在线安装 得下载源代码 然后运行 标注好数据保存会是一个xml文件 2.把xml文件转换成dota的xml文件&#xff0c;然后把dota的xml文件转换成dota的txt文件…

Select 选择器 el-option 回显错误 value

离谱 回显的内容不是 label 而是 value 的值 返回官方看说明&#xff1a; v-model的值为当前被选中的el-option的 value 属性值 value / v-model 绑定值有3种类型 boolean / string / number 根据自身代码猜测是&#xff1a;tableData.bookId 与 item.id 类型不一致导致 &…

Vue源码系列讲解——变化侦测篇【下】(Array的变化侦测)

目录 1. 前言 2. 在哪里收集依赖 3. 使Array型数据可观测 3.1 思路分析 3.2 数组方法拦截器 3.3 使用拦截器 4. 再谈依赖收集 4.1 把依赖收集到哪里 4.2 如何收集依赖 4.3 如何通知依赖 5. 深度侦测 6. 数组新增元素的侦测 7. 不足之处 8. 总结 1. 前言 上一篇文…

mysql入门到精通005-基础篇-约束

1、概述 1.1 概念 约束是作用于表中字段上的规则&#xff0c;用于限制储存在表中的数据。 1.2 目的 保证数据库中数据的正确性、有效性和完整性。 1.3 常见的约束分类 一旦谈到外键&#xff0c;则至少涉及2张表约束是作用于表中字段上的&#xff0c;可以在创建表/修改表的…

c++设计模式之代理模式

作用 代理模式主要用于&#xff0c;通过代理类&#xff0c;来控制实际对象的访问权限 案例 class VideoSite { public:virtual void freeVideo()0;virtual void vipVideo()0;virtual void trickVideo()0; };class FixBugVideoSite:public VideoSite { public:void freeVideo()…

双非本科准备秋招(19.2)—— 设计模式之保护式暂停

一、wait & notify wait能让线程进入waiting状态&#xff0c;这时候就需要比较一下和sleep的区别了。 sleep vs wait 1) sleep 是 Thread 方法&#xff0c;而 wait 是 Object 的方法 2) sleep 不需要强制和 synchronized 配合使用&#xff0c;但 wait 强制和 s…

《Git 简易速速上手小册》第10章:未来趋势与扩展阅读(2024 最新版)

文章目录 10.1 Git 与开源社区10.1.1 基础知识讲解10.1.2 重点案例&#xff1a;Python 社区使用 Git10.1.3 拓展案例 1&#xff1a;Git 在大型开源项目中的角色10.1.4 拓展案例 2&#xff1a;支持开源项目的 Git 托管平台 10.2 新兴技术与 Git 的整合10.2.1 基础知识讲解10.2.2…

高并发对于服务器性能有什么要求?

随着互联网的普及和应用程序的复杂度增加&#xff0c;高并发已经成为许多应用程序必须面对的问题。高并发是指在短时间内有大量用户同时访问应用程序或数据库&#xff0c;对服务器性能提出了更高的要求。本文将探讨高并发对于服务器性能的要求。 一、高并发对服务器硬件的要求…

瑞_力扣LeetCode_二叉树相关题

文章目录 说明题目 144. 二叉树的前序遍历题解 题目 94. 二叉树的中序遍历题解 题目 145. 二叉树的后序遍历题解 题目 105. 从前序与中序遍历序列构造二叉树题解 题目 106. 从中序与后序遍历序列构造二叉树题解 &#x1f64a; 前言&#xff1a;本文章为瑞_系列专栏之《刷题》的…

HTML5+CSS3+移动web——HTML 基础

目录 一、标签语法 HTML的基本框架 1. 标题标签 2. 段落标签 3. 换行和水平线 4. 文本格式化标签 5. 图像标签 6. 路径 相对路径 绝对路径 7. 超链接标签 8. 音频 9. 视频 10. 注释 二、标签结构 一、标签语法 HTML 超文本标记语言——HyperText Markup Langua…

Hadoop3.x基础(4)- Yarn

来源&#xff1a;B站尚硅谷 目录 Yarn资源调度器Yarn基础架构Yarn工作机制作业提交全过程Yarn调度器和调度算法先进先出调度器&#xff08;FIFO&#xff09;容量调度器&#xff08;Capacity Scheduler&#xff09;公平调度器&#xff08;Fair Scheduler&#xff09; Yarn常用命…