2.8 C++STL set/multiset容器详解

本文详细介绍了C++中的Set和Multiset容器,它们是基于红黑树实现的集合,Set不允重复元素,Multiset允许。文章通过代码示例展示了如何初始化、赋值、删除、查找等操作,并探讨了如何自定义排序规则。同时,还补充了关于对组Pair的使用,包括创建、赋值和查找操作。最后,对比了Set与unordered_set的区别,强调了它们在数据结构和性能上的差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


2.8.1 引入

set/multiset容器概念

  • set和multiset是一个集合容器,其中set所包含的元素是唯一的,集合中的元素按一定的顺序自动排列。set采用红黑树变体的数据结构实现,红黑树属于平衡二叉树。在插入操作和删除操作上比vector快。在n个数中查找目标数的效率是 log 2 n

  • set容器中不允许重复元素,multiset允许重复元素。

  • 只提供Insert方法初始化,如下图。

    image-20211012223856316

    set常用API见set 常用API_qq_41050821的博客-CSDN博客

2.8.2 代码示例

#include<iostream>
#include<set>
using namespace std;

//仿函数
class mycompare
{
public:
	bool operator()(int v1,int v2)const
	{
		return v1 > v2;
	}
	//这里要加上const ,原视频vs2019会报错,详情见 https://www.cnblogs.com/qrlozte/p/4437418.html
};

//初始化
void text01()
{
	set<int> s1;//自动进行排序,默认从小到大。
	s1.insert(7);
	s1.insert(2);
	s1.insert(4);
	s1.insert(5);
	s1.insert(1);
	s1.insert(9);

	for (set<int>::iterator it = s1.begin(); it != s1.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;

	//赋值操作
	set<int> s2;
	s2 = s1;

	//删除操作
	s1.erase(s1.begin());
	s1.erase(7);
	for (set<int>::iterator it = s1.begin(); it != s1.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;

	//如何改变默认排序,从大到小。//先序遍历,中序遍历,后序遍历。
	//借助仿函数
	mycompare com;
	com(20, 30);

	set<int, mycompare> s3;//自动进行排序,默认从小到大。
	s3.insert(7);
	s3.insert(2);
	s3.insert(4);
	s3.insert(5);
	s3.insert(1);
	s3.insert(9);
	for (set<int/*,mycompare*/>::iterator it2 = s3.begin(); it2 != s3.end(); it2++)
	{
		cout << *it2 << " ";
	}
	cout << endl;
}

//查找
void text02()
{
	//实值
	set<int> s1;
	s1.insert(7);
	s1.insert(2);
	s1.insert(4);
	s1.insert(5);
	s1.insert(1);
	s1.insert(9);

	set<int>::iterator ret = s1.find(4);//不存在返回end()的值
	if (ret == s1.end())
	{
		cout << "没有找到" << endl;
	}
	else
	{
		cout << "ret:" << *ret << endl;
	}

	//lower_bound(2)找第一个大于等于k的(元素)迭代器值
	ret = s1.lower_bound(2);
	if (ret == s1.end())
	{
		cout << "没有找到" << endl;
	}
	else
	{
		cout << "ret:" << *ret << endl;
	}

	//找第一个大于K的值
	ret = s1.upper_bound(2);
	if (ret == s1.end())
	{
		cout << "没有找到" << endl;
	}
	else
	{
		cout << "ret:" << *ret << endl;
	}

	//equal_range 返回Lower_bound 和 upper_bound值
	pair<set<int>::iterator, set<int>::iterator> myret = s1.equal_range(2);
	//这里用到了pair我们在下面补充对组的相关内容。
	/*myret.first;
	myret.second;*/
	if (myret.first == s1.end())
	{
		cout << "can't find" << endl;
	}
	else
	{
		cout << "myret:" << *myret.first << endl;//返回Lower_bound
	}
	if (myret.second == s1.end())
	{
		cout << "can't find" << endl;
	}
	else
	{
		cout << "myret:" << *myret.second << endl; //返回upper_bound
	}
}

class Person
{
public:
	Person(int age, int id):id(id),age(age){}
public:
	int id;
	int age;
};

class mycompare2
{
public: 
	bool operator()(Person p1, Person p2)const
	{
		return p1.age > p2.age;
	}
};

void text03()
{
	set<Person,mycompare2> sp;

	Person p1(10, 20), p2(30, 40), p3(50, 60);
	sp.insert(p1);
	sp.insert(p2);
	sp.insert(p3);

	Person p4(10, 20);
	for (set<Person, mycompare2>::iterator it = sp.begin(); it != sp.end(); it++)
	{
		cout << (*it).age << " " << (*it).id << endl;
	}

	//查找
	sp.find(p1);
	sp.find(p4);
	auto ret = sp.find(p4);//set<Person,mycompare2>::iterator
	if (ret == sp.end())
	{
		cout << "can't find" << endl;
	}
	else
	{
		cout << "find:" << (*ret).id << " " << (*ret).age << endl;
	}
}

int main()
{
	cout <<"text01:"<< endl;
	text01();
	cout << "text02:" << endl;
	text02();
	cout << "text03:" << endl;
	text03();
	return 0;
}

2.8.3 代码运行结果

image-20211013092413380

2.8.4 对组pair的补充

代码实例
//对组的相关内容补充
#include<iostream>
#include<string>
using namespace std;

void text01()
{
	//创建对组
	//法一
	pair<string, int> pair1(string("number"), 20);
	cout << pair1.first << " " << pair1.second << endl;
	
	//或者pair<string,int> pair2=make_pair("name",30)
	pair<string, int> pair2 = make_pair("name", 30);
	cout << pair2.first << " " << pair2.second << endl;

	//pair赋值
	pair<string, int> pair3 = pair2;
	cout << pair2.first << " " << pair2.second << endl;
}

int main()
{
	text01();
	return 0;
}
运行结果

image-20211013082837467

总结

在刷力扣时,我们发现c++11中的unordered_set也非常常用,我们对比一下就会发现如下结论。

  • c++ std中set与unordered_set区别和map与unordered_map区别类似,其底层的数据结构说明如下:

1、set基于红黑树实现,红黑树具有自动排序的功能,因此map内部所有的数据,在任何时候,都是有序的。

2、unordered_set基于哈希表,数据插入和查找的时间复杂度很低,几乎是常数时间,而代价是消耗比较多的内存,无自动排序功能。底层实现上,使用一个下标范围比较大的数组来存储元素,形成很多的桶,利用hash函数对key进行映射到不同区域进行保存。

详情见c++ set与unordered set的区别 - 阿玛尼迪迪 - 博客园 (cnblogs.com)


谢谢阅读(〃’ ▽ '〃)如有纰漏欢迎指出,觉得还不错就点个赞吧。

SQL Server 中,`EXISTS` 是一个用于检查是否存在符合特定条件的记录的逻辑运算符。`EXISTS` 返回一个布尔值,即 `TRUE` 或 `FALSE`,表示查询结果集是否包含匹配条件的记录。下面是 `EXISTS` 的详细用法: 1. 基本语法: ```sql SELECT column_name(s) FROM table_name WHERE EXISTS (SELECT column_name FROM table_name WHERE condition); ``` 2. 示例: 假设有两个表,分别为 `customers` 和 `orders`, `customers` 表中包含了所有客户的信息,而 `orders` 表中包含了所有的订单信息。我们需要查询所有已经下过订单的客户的姓名和地址,可以使用以下 SQL 语句: ```sql SELECT customerName, address FROM customers WHERE EXISTS (SELECT * FROM orders WHERE orders.customerID = customers.customerID); ``` 在上面的 SQL 语句中,`EXISTS` 子查询中的条件是查找 `orders` 表中的所有记录,其中 `orders.customerID = customers.customerID` 表示连接两个表的条件,即匹配两个表中的 `customerID` 列。如果 `EXISTS` 子查询返回 `TRUE`,则 `customerName` 和 `address` 列的值会被返回。 3. 注意事项: - `EXISTS` 子查询必须包含一个 `SELECT` 语句,该语句必须返回一个结果集。 - `EXISTS` 子查询中的条件必须使用外部查询中的列或表。 - `EXISTS` 子查询中的 `SELECT` 语句可以是任何有效的 T-SQL 查询语句,包括 `SELECT *`。 - `EXISTS` 子查询中的条件可以包含任何有效的 T-SQL 表达式和运算符。 - `EXISTS` 的性能比使用 `JOIN` 进行连接查询要高,特别是在查询大型数据集时。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

一只子美

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

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

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

打赏作者

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

抵扣说明:

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

余额充值