这是我的第一篇掘金博客,开启掘金写作之路。
set 集合容器简介
set 是我们常用的数据结构,用来存储同一数据类型,并提供常用的数据操作。
set 的基本特点
- 头文件为
#include<set> set中的元素都是自动排好序的set集合中没有重复的元素,即元素的值都唯一- 只能通过迭代器
set<int>::iterator访问集合元素
set中的元素是如何实现自动排序的呢?
set 集合容器实现了红黑树的平衡二叉检索树的数据结构,在插入元素时,会自动调整二叉树的排列,把该元素放到适当的位置,以确保每个子树根节点的键值大于左子树所有节点的键值,而小于右子树所有节点的键值;
这样存放的目的在于查找时能够快速检索,因为
set在查找时使用的是二分查找,时间复杂度为 。
同时 set 集合还确保根节点的左子树的高度与右子树的高度平衡,这样,二叉树的高度最小,从而检索速度最快。需要注意的是,它不会重复插入相同键值的元素,而采取忽略处理。平衡二叉检索树的检索使用中序遍历算法,检索效率高于 vector、deque、和 list 的容器。
set常用的函数方法
| 函数方法 | 函数功能 |
|---|---|
| begin() | 返回指向第一个元素的迭代器 |
| end() | 返回指向最后一个元素的迭代器 |
| clear() | 清除所有元素 |
| count() | 返回某个值元素的个数 |
| empty() | 判断集合是否为空 |
| erase() | 删除集合中的元素,删除的可以是指向的迭代器也可以是元素值 |
| find() | 返回一个指向被查找到元素的迭代器 |
| insert() | 在集合中插入元素 |
| lower_bound() | 返回指向大于等于某值的第一个元素的迭代器,如果没找到,返回末尾的迭代器位置 |
| upper_bound() | 返回大于某个值元素的迭代器,如果没找到,返回末尾的迭代器位置 |
| max_size() | 返回集合能容纳的元素的最大限值 |
| rbegin() | 返回指向集合中最后一个元素的反向迭代器 |
| rend() | 返回指向集合中第一个元素的反向迭代器 |
| size() | 集合中元素的数目 |
| swap() | 交换两个集合变量 |
在什么情况使用 set 集合容器?
构造 set 集合的主要目的是为了快速检索。所以当我们需要对某个集合总的元素进行大量的查找、添加、删除操作时可以选择使用 set 集合容器。
这里需要注意的是
set集合中的元素不能直接被修改。
set 集合使用案例分析:
题目链接:LCP 52. 二叉搜索树染色
题目大意: 对一颗二叉树上的节点值进行多次区间染色,返回最后染色情况。(这里只对题目做简单描述,题目完整描述可以点击链接查看,主要为了说明 set 集合的使用情况)
示例:
输入:root = [4,2,7,1,null,5,null,null,null,null,6]
ops = [[0,2,2],[1,1,5],[0,4,5],[1,5,7]]
输出:5
解释:
第 0 次操作,将值为 2 的节点染蓝;
第 1 次操作,将值为 1、2、4、5 的节点染红;
第 2 次操作,将值为 4、5 的节点染蓝;
第 3 次操作,将值为 5、6、7 的节点染红;
因此,最终值为 1、2、5、6、7 的节点为红色节点,返回数量 5
解题思路分析:
- 因为我们要对某区间进行多次修改和查询,常规做法是需要使用线段树进行完成,但是犹豫线段树代码非常冗长,查代码也比较困难,对于很多没有接触过线段树的人来说更是无法完成。
- 但是该题还可以仅通过使用
set集合来完成,因为每个点的颜色只取决于最后一次染色操作。所以我们可以用set维护所有颜色待确定的点,倒序处理询问,每次利用lower_bound()方法从set中取出所有在询问范围内的点染色后删掉。因为每个点只会被删掉一次,所以总体复杂度 ,其中n是节点数量,q是询问数量。
小结: 该题通过巧妙的思维和灵活的使用了 set 集合以及内置函数 lower_bound() 方法,将看似无法解决的困难题目化解,这也充分体现了 set 集合的检索效率。
set 迭代器的声明方式以及使用
#include<bits/stdc++.h>
#include<set>
using namespace std;
int main(){
//创建一个int类型的集合s
set<int> s;
//定义正向迭代器
set<int>::iterator it;
//中序遍历集合中的所有元素(从小到大)
for(it = s.begin(); it != s.end(); it++) cout << *it << " ";
//定义反向迭代器
set<int>::reverse_iterator rit;
//从大到小
for(rit = s.rbegin(); rit != s.rend(); rit++) cout << *rit << " ";
return 0;
}
注意: 使用反向迭代器
reverse_iterator可以反向遍历集合,用到rbegin()和rend()两个方法。
set 使用总结
- 判断
set集合中某个元素是否存在时通常有两种操作可以实现:- 使用
find()方法对集合进行检索,如果找到查找的的键值,则返回该键值的迭代器位置;否则,返回集合最后一个元素后面的一个位置,即end()。通常判断语句为:
if(s.find(x) != s.end());//set<int> s;- 也可以使用
count(x)函数来判断集合中是否存在值为x的元素。(因为set集合不会重复插入,所以集合中每个元素的count()要么为0要么为1)
if(s.count(x) == 1);//set<int> s; - 使用
- 判断
set集合是否为空也有两种常用操作:- 使用
empty()方法直接判断是否为空:
if(s.empty());//set<int> s;- 使用
size()方法判断集合中元素的数目是否为0:
if(s.size() > 0);//set<int> s; - 使用
结束语
真正的失败,是你决定放弃的那一刻;这世上没有凭空而起的楼阁,也没有平白无故的成功;最好的时光,永远是现在。