c++中的set容器和multiset容器

本文介绍了C++中的set和multiset容器,它们都是关联式容器,内部基于红黑树实现。set保证每个元素唯一且自动排序,不允许修改元素值;而multiset允许存储重复元素。讨论了set的主要方法,如insert、erase、find等,并提到了自定义数据类型的排序和判断插入操作是否成功的方法。此外,还简述了multiset作为set的补充,可以存储相同数据的特点。

set关联式容器。set作为一个容器也是用来存储同一数据类型的数据类型,并且能从一个数据集合中取出数据,在set中每个元素的值都唯一,而且系统能根据元素的值自动进行排序。应该注意的是set中数元素的值不能直接被改变。C++ STL中标准关联容器set, multiset, map, multimap内部采用的就是一种非常高效的平衡检索二叉树:红黑树,也成为RB树(Red-Black Tree)。RB树的统计性能要好于一般平衡二叉树,所以被STL选择作为了关联容器的内部结构
set的常用方法:
添加元素:
insert()
删除元素:
clear()    ,删除set容器中的所有的元素
erase()
查找元素:
set.find(…) ,查找元素位置并返回位置

begin()     ,返回set容器的第一个元素
end()       ,返回set容器的最后一个元素
set.count(5) ,统计集合中元素等于5的元素个数
empty()     ,判断set容器是否为空
max_size()   ,返回set容器可能包含的元素最大个数
size()      ,返回当前set容器中的元素个数
rbegin     ,返回的值和end()相同
rend()     ,返回的值和rbegin()相同
1.添加元素和删除元素

//set元素的添加/遍历/删除基本操作
void Demo1()
{
	set<int> Set;
	for (int i = 0; i < 10; i++)
	{
		Set.insert(i + 1);//set集合没有push()函数,不能按照[]方式添加元素 ,只能用insert插入添加元素
	}
	Set.insert(100);//不能添加重复元素,元素唯一
	Set.insert(100);
	Set.insert(100);
	for (set<int>::iterator it = Set.begin(); it != Set.end(); it++)
	{
		cout << *it << " ";//自动排序(默认情况下 是从小到大)
	}
	cout << endl;
	//删除
	while(!Set.empty())
	{
		Set.erase(Set.begin());
	}
	cout << Set.size() << endl;
}

2 对基本的数据类型 set能自动的排序

void Demo2()
{
	set<int> set1;//从小到大(简写)
	set<int, less<int>> set2;   //默认情况下是这样 ,从小到大

	set<int, greater<int>> set3;  //从大 到 小
	for (int i = 0; i < 10; i++)
	{
		set3.insert(rand());//随机插入整数
	}
	for (set<int, greater<int>>::iterator it = set3.begin(); it != set3.end(); it++)
	{
		cout << *it << " ";
	}
}

3.自定义数据类型 排序

//03 仿函数 函数对象 重载() 操作 进行比较大小
//题目:学生包含学号,姓名属性,现要求任意插入几个学生对象到set容器中,使得容器中的学生按学号的升序排序
class student
{
public:
	int age;
	char *name;
	student(int _age, char *_name)
	{
		age = _age;
		name = _name;
	}
	void print()
	{
		cout << "age:" << age << "    name:" << name << endl;
	}
};
//伪函数
struct  Function//伪函数一般使用struct,因为struct默认为public。如果用class的话必须标明是public类,因为class默认为private类型
{
	bool operator()(const student &left, const student &right)//返回bool类型
	{
		if (left.age > right.age)//左边大返回true,从大到小排列
		{
			return true;
		}
		return false;
	}
};
void Demo3()
{
	student t1(22, "Christine22"), t2(23, "Christine23"), t3(24, "Christine24"),t4(24, "Christine24");
	set<student, Function> set1;//对于类元素的排序,需要传入伪函数作为比较的函数,伪函数就是重载了函数()的结构体。第一个参数也应该改为传入自定义参数的类
	set1.insert(t1);
	set1.insert(t2);
	set1.insert(t3);
	set1.insert(t4);
	for (set<student, Function>::iterator it = set1.begin(); it != set1.end(); it++)
	{
		cout << it->age << "\t " << it->name << " " << endl;
	}
}

4.判断 set1.insert()函数是否插入成功

//typedef pair<iterator, bool> _Pairib;
//Pair的用法 
void Demo4()
{
	student t1(11, "Christine"), t2(23, "Christine"), t3(2654, "Christine"), t4(4, "Christine"), t5(11, "Christine");
	set<student, Function> set1;
	set1.insert(t1);
	set1.insert(t2);
	set1.insert(t3);
	set1.insert(t4);
	pair<set<student, Function>::iterator, bool> pair = set1.insert(t5);
	if (pair.second==true)//通过判断pair返回的第二个值
	{
		cout << "插入t5成功" << endl;
	}
	else
	{
		cout << "插入t5失败" << endl;
	}
}

5.find查找

//find查找  equal_range 
//返回结果是一个pair
void Demo5()
{
	set<int> set1;
	for (int i = 0; i<10; i++)
	{
		set1.insert(i + 1);
	}
	for (set<int>::iterator it = set1.begin(); it != set1.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
	set<int>::iterator it0 = set1.find(5);//查找元素5的位置
	cout << "it0:" << *it0 << endl;

	int num1 = set1.count(5);//统计集合中元素等于5的元素个数
	cout << "num1:" << num1 << endl;

	//算法lower_bound返回区间A的第一个迭代器,算法upper_bound返回区间A的最后一个元素的下一个位置,算法equal_range则是以pair的形式将两者都返回
	set<int>::iterator it1 = set1.lower_bound(6); // 大于等于6的元素的 迭代器的位置
	cout << "大于等于6的元素迭代器位置  it1:" << *it1 << endl;
	set<int>::iterator it2 = set1.upper_bound(6); // 大于6的元素 的 迭代器的位置
	cout << "大于6的元素的迭代器的位置  it2:" << *it2 << endl;

	//把5元素删除掉
	set1.erase(5);
	for (set<int>::iterator it = set1.begin(); it != set1.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
	//算法lower_bound返回区间A的第一个迭代器,算法upper_bound返回区间A的最后一个元素的下一个位置,算法equal_range则是以pair的形式将两者都返回
	pair<set<int>::iterator, set<int>::iterator>  pair = set1.equal_range(6);//pair会返回两个迭代器,equal_range就是返回两个迭代器,第一个是大于等于,第二个是大于
	set<int>::iterator it3 = pair.first;//从前往后找(第一个迭代器)
	cout << "it3:" << *it3 << endl;  //6  

	set<int>::iterator it4 = pair.second;//从后往前找(第二个迭代器)
	cout << "it4:" << *it4 << endl;  //7  
}

multiset是可以将相同元素放进容器的容器,是set容器的补充(multiset相对于set而言可以存相同数据)

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
#include "set"
void main10()
{
	multiset<int> set1;//multiset相对于set而言可以存相同数据
	int tmp = 0;

	printf("请输入multiset集合的值:");
	scanf("%d", &tmp);
	while (tmp != 0)
	{
		set1.insert(tmp);
		printf("请输入multiset集合的值:");
		scanf("%d", &tmp);
	}

	//遍历
	for (multiset<int>::iterator it = set1.begin(); it != set1.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;

	while (!set1.empty())
	{
		multiset<int>::iterator it = set1.begin();
		cout << *it << " ";
		set1.erase(it);
	}
}
### C++ `set` `multiset` 容器的区别及使用场景 #### 1. 基本概念与特点 - **`std::set`** 是一种关联式容器,用于存储唯一的、按特定顺序排列的元素集合。它通过内部机制(通常是红黑树)来保持元素的有序性唯一性[^1]。 - **`std::multiset`** 同样是一种关联式容器,但它允许存储重复的元素。除了这一点外,`multiset` 的行为与 `set` 类似,同样会根据指定的排序规则对元素进行排序[^2]。 #### 2. 数据结构实现 两种容器都基于平衡二叉查找树(如红黑树)实现,因此提供了高效的插入、删除查找操作,时间复杂度均为 O(log n)[^3]。 #### 3. 主要区别 | 特性 | `std::set` | `std::multiset` | |---------------------|------------------------------------|-------------------------------------| | 元素唯一性 | 所有元素必须唯一 | 可以存在多个相同的元素 | | 排序 | 按照指定的排序规则 | 按照指定的排序规则 | | 插入/删除效率 | 较高 | 较高 | | 查找效率 | 高 | 高 | #### 4. 使用场景 - 如果需要维护一个不包含重复项且始终有序的集合,则应选择 `std::set`[^1]。 - 当希望保留某些元素多次出现的情况,并仍然维持这些元素的有序性时,可以选择 `std::multiset`。 #### 5. 示例代码对比 以下是两个容器的基本用法示例: ##### `std::set` 示例 ```cpp #include <iostream> #include <set> int main() { std::set<int> mySet; mySet.insert(1); mySet.insert(2); mySet.insert(2); // 不会被插入,因为已存在 for (const auto& elem : mySet) { std::cout << elem << " "; } } // 输出: 1 2 ``` ##### `std::multiset` 示例 ```cpp #include <iostream> #include <set> int main() { std::multiset<int> myMultiSet; myMultiSet.insert(1); myMultiSet.insert(2); myMultiSet.insert(2); // 被插入两次 for (const auto& elem : myMultiSet) { std::cout << elem << " "; } } // 输出: 1 2 2 ``` #### 6. 性能考量 尽管两者的时间复杂度相似,但由于 `std::set` 需要额外检查元素是否存在以确保唯一性,在频繁插入大量数据的情况下可能会稍微影响性能。而如果不需要关心元素唯一性的场合下,`std::multiset` 则更为灵活适用。 --- 相关问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值