C++: set容器

一、关联式容器

我们已经了解了STL中的部分容器,比如vector、list、deque等,这些容器被称为序列式容器,其底层为线性序列的数据结构,里面存储的是元素本身

关联式容器也是用来存储数据的,与序列式容器不同,关联式容器里面存储的是Key - Value结构的键值对,在数据检索时比序列式容器效率高

二 、键值对

键值对是用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量Key和Value,Key代表键值, Value代表与Key对应的信息。

键值对在STL中被定义成一个pair类型,如下所示:

struct pair
{
	typedef T1 first_type;
	typedef T2 second_type;

	T1 first;
	T2 second;
	pair()
		:first(T1())
		,second(T2())
	{}

	pair(const T1& a, const T2& b)
		:first(a)
		,second(b)
	{}
};

三、树状结构的关联式容器

STL中对关联式容器实现了两种不同结构的版本,以适应不同的场景:树状结构和哈希结构。这里主要介绍树状结构为底层的关联式容器。

树状结构的关联式容器主要有4种:map、set、multimap、multiset。

以上四种容器的共同点是:其底层都是使用**平衡二叉搜索树(即红黑树)**实现的,容器中的元素是一个有序的序列。

3.1 set

3.1.1 set的使用

set文档介绍

  1. set是按照一定次序存储元素的容器。
  2. 在set中元素的Value就是Key,并且每个Value必须是唯一的。
  3. 在内部,set的元素总是按照其内部比较对象(类型比较)所指示的特定严格弱排序准则进行排序的。
  4. set容器通过Key访问某个单个元素的效率通常会比unordered_set容器要慢,但是它允许按顺序对子集进行迭代。
  5. set的底层是由红黑树实现的。

注意:

  • 与map/multimap不同,map/multimap中存储的是真正的键值对pair<Key, Value>,set中只放Value但是在底层存放的是<value, value>的键值对。
  • set在插入元素的时候,只需要插入Value即可,不需要构造键值对。
  • set中的元素不可以重复(可以用set进行去重)。
  • 使用set的迭代器遍历set中的元素,可以得到有序序列。
  • set中的元素默认按小于比较,也就是升序排列。
  • set中查找某个元素的效率是O(logN)。
  • set中的元素不允许被修改。
  • set的底层是由二叉搜索树(红黑树)实现的。

set的迭代器走的是中序遍历,是一个双向迭代器,set:去重+排序

3.1.2 set的使用

1.set的模版参数

以上就是set的模版参数,我们来看下第一个模版参数,T:set中存放的元素类型,在底层的存储实际上是<value, value> 的键值对。

第二个模版参数Compare:set中用于比较的仿函数,set中的元素默认按照小于进行比较。

第三个模版参数:set中元素空间的管理方式,使用STL提供的空间配置器进行管理。

2.set的构造函数

函数声明功能介绍
explicit set (const key_compare& comp = key_compare(),
const allocator_type& alloc = allocator_type());
构造空的set
template
set (InputIterator first, InputIterator last,
const key_compare& comp = key_compare(),
const allocator_type& = allocator_type());
使用[first, last)的迭代器区间中的元素进行构造set
set (const set& x);
set (const set& x, const allocator_type& alloc);
set的拷贝构造
void test_set()
{
	set<int> s1;//构造一个空set
	vector<int> v1;
	for (int i = 10; i >= 0; i--)
	{
		v1.push_back(i);
	}
	set<int> s2(v1.begin(), v1.end());//迭代器区间构造
	for (auto e : s2)
	{
		cout << e << " ";
	}
	cout << endl;
}

int main()
{
	test_set();
	return 0;
}

3.set的迭代器

函数声明功能介绍
iterator begin()返回set起始位置元素的迭代器
iterator end()返回set最后一个元素后一个位置的迭代器
const_iterator cbegin() const返回set起始位置的const迭代器
const_iterator cend() const返回set最后一个元素的后一个位置的const迭代器
reverse_iterator rbegin()返回set的第一个反向迭代器,也就是最后一个元素的后一个位置的迭代器,相当于end()
reverse_iterator rend()返回set的最后一个反向迭代器,也及时第一个元素位置的迭代器,相当于begin()
const_reverse_iterator crbegin() const返回set的第一个反向const迭代器,也就是最后一个元素的后一个位置的const迭代器,相当于cend()
const_reverse_iterator crend() const返回set的最后一个反向const迭代器,也及时第一个元素位置的const迭代器,相当于cbegin()
void test_set1()
{
	set<int> s1{ 1, 2, 3, 4, 5, 7, 0, 8 ,9 ,10, 12 };
	set<int>::iterator it = s1.begin();
	while (it != s1.end())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;

	auto it1 = s1.rbegin();
	while (it1 != s1.rend())
	{
		cout << *it1 << " ";
		it1++;
	}
	cout << endl;
}

迭代器补充:

函数声明函数功能
iterator lower_bound(x)返回 >= x 的值的位置的迭代器(左边界)
iterator upper_bound(y)返回 > y 的值的位置的迭代器 (右边界)
void test_set2()
{
	set<int> s1{ 1, 2, 3, 4, 5, 7, 0, 8 ,9 ,10, 12 };

	set<int>::iterator it = s1.lower_bound(2);//左边界
	set<int>::iterator it1 = s1.upper_bound(10);//右边界
	//相当于输出2 - 10之间的数字
	while (it != it1)
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;
}

4.set的容量接口

函数声明功能介绍
bool empty() const检测set是否为空,如果为空就返回true,否则返回false
size_type size() const返回set中的有效元素个数
void test_set1()
{
	set<int> s1{ 1, 2, 3, 4, 5, 7, 0, 8 ,9 ,10, 12 };
	cout << s1.empty() << endl;
	cout << s1.size() << endl;
}

5.set的修改操作接口

函数声明功能介绍
pair<iterator, bool> insert(const value_type& x)在set中插入元素x,实际插入的是<x, x>构成的键值对,如果插入成功,就返回<该元素在set中的位置的迭代器,true>, 如果插入失败,就代表x在set中已经存在,返回<x在se中的位置的迭代器,false>
void erase(iterator pos)删除set中在pos位置的元素
size_type erase(const key_type& x)删除set中值为x的元素,返回删除的元素的个数
void erase(iterator first, iterator last)删除set中[first, last)区间中的元素
void swap(set<Key, Compare, Allocator>& st)交换两个set中的元素
void clear()将set中的元素清空
iterator find(const Key_type& x) const返回set中值为x的元素的位置
size_type count(const Key_type& x) const返回set中值为x的元素的个数
void test_set3()
{
	set<int> s1;
	s1.insert(1);
	s1.insert(3);
	s1.insert(1);
	s1.insert(5);
	s1.insert(7);
	s1.insert(10);
	s1.insert(11);
	s1.insert(6);
	s1.insert(12);
	s1.insert(13);
	s1.insert(19);
	s1.insert(100);
	for (auto e : s1)
	{
		cout << e << " ";
	}
	cout << endl;
	s1.erase(100);//按值删除
	for (auto e : s1)
	{
		cout << e << " ";
	}
	cout << endl;
	s1.erase(s1.begin());//按位删除
	for (auto e : s1)
	{
		cout << e << " ";
	}
	cout << endl;
	s1.erase(s1.begin(), ++s1.begin());//按迭代器区间删除
	for (auto e : s1)
	{
		cout << e << " ";
	}
	cout << endl;
	auto it1 = s1.find(6);//查找值为位置返回值所在位置的迭代器
	cout << *it1 << endl;

	cout << s1.count(6) << endl;//返回值在set中出现的次数
	set<int> s2{ 1, 2, 3, 4, 5 };
	s1.swap(s2);//交换两个set中的元素
	for (auto e : s1) cout << e << " ";
	cout << endl;
	for (auto e : s2) cout << e << " ";
	cout << endl;
	s1.clear();
	cout << s1.empty();
	cout << endl;
	s2.clear();
	cout << s2.empty();
	cout << endl;
}

3.2 multiset

multiset文档介绍

multiset 大致与set相同,但是multi系列允许键值冗余,也就是说multiset中的数据可以重复。

multiset也可以走中序遍历进行排序,但是不能进行去重。

接口方面和set基本相同。这里就不在重复介绍了。

关于set的使用的介绍到这里就结束了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

凪よ

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

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

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

打赏作者

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

抵扣说明:

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

余额充值