c++ set和multiset的使用

本文介绍了C++中的set和multiset容器,它们是有序且不允许重复的集合。set由红黑树实现,提供快速的插入和删除操作,但不支持直接访问元素。multiset允许元素重复,其元素排序依据内置或自定义的比较函数。内容涵盖了set和multiset的基本操作,包括构造函数、排序方式、插入、删除和查找等。

1. 介绍

  • set是一个集合容器,其中所包含的元素是唯一的, 集合中的元素按一定的顺序排列。
  • 由于本身是有序的,因此不能指定元素的插入位置
  • set是由变体的红黑树实现的。因此插入和删除操作比vector快
  • set不支持直接存取元素,即不能通过 [] 操作符或at() 方法访问元素
  • 不可以直接修改set和multiset中元素值,只能通过先删除在插入的方式修改
  • 即set和multiset中元素类型都是const的
  • set和multiset采用 < 操作符进行默认排序
  • #include< set>

multiset与set区别:

  • set中key唯一,只能出现一次;而multiset中key不唯一,可以重复出现

2. 额外类型说明

类型名含义
key_type表示set中关键字(key)的类型
value_type与key_type相同

3. set/multiset构造函数

默认构造函数:

set<int> set_i;
set<string> set_s;

multiset<int> mulset_i;

set的拷贝构造和赋值:

set<int> setIntA;
setIntA.insert(3);
setIntA.insert(1);

set<int> setIntB(setIntA);   // 拷贝构造

set<int> setIntC;
setIntC = setIntA;   // 赋值构造,set重载了=操作符

4. set的排序方式与自定义排序

按升序方式排列:

set<int, less<int>> set1;
set1.insert(3);
set1.insert(2);
set1.insert(1);  // 此时set1为1,2,3升序

按降序方式排列:

set<int, greater<int>> set2;
set2.insert(1);
set2.insert(2);
set2.insert(3);  // 此时set2为3,2,1降序

// grater的具体实现如下
struct greater
{
	bool operator() (const int& iLeft, const int& iRight)  // 重载()操作符
	{
		return (iLeft>iRight); //如果是实现 less<int>的话,这边是写 return (iLeft<iRight);
	}
}

上面的lessgreater 是stl中内置的函数对象,我们也可以根据需求自定义排序方式
自定义方式一:重载()运算符

// 学生类
class CStudent {
public:
	CStudent(int id_n, string strName)	{
		m_id = id_n; 
		m_strName = strName;
	}
	int m_id; //学号
	string m_strName; //姓名
};

// 定义比较对象,重载()运算符
struct StuFunctor {
	bool operator() (const CStudent &stu1, const CStudent &stu2){
		return (stu1.m_iID<stu2.m_iID);
	}
};

// 调用
set<CStudent, StuFunctor> set_stu;   // 定义set,传入比较对象
// 根据id升序排序
set_stu.insert(CStudent(3, "df"));
set_stu.insert(CStudent(1, "ewdf"));   

自定义方式二:定义比较函数,传入函数指针

// 学生类
class CStudent {
public:
	CStudent(int id_n, string strName)	{
		m_id = id_n; 
		m_strName = strName;
	}
	int m_id; //学号
	string m_strName; //姓名
};

// 定义比较函数
bool compareId() (const CStudent &stu1, const CStudent &stu2){
	return (stu1.m_iID<stu2.m_iID);
}

// 调用
// 定义set,传入比较函数的指针
// decltype指出自定义操作的类型,必须使用*来指定获取函数类型的指针
set<CStudent, decltype(compareId)*> set_stu;   
// 根据id升序排序
set_stu.insert(CStudent(3, "df"));
set_stu.insert(CStudent(1, "ewdf"));   

5. set插入与迭代器

操作说明
p.insert(v)
p.emplace(args)
v是value_type类型;args用来构造一个元素。
只有当元素不存在时才插入
函数返回一个pair<iterator, bool>,其中迭代器是指向具有指定关键字的元素,bool表示是否插入成功
对于multiset,总会插入给定元素,并返回一个指向新元素的迭代器
p.insert(begin, end)
p.insert(il)
begin和end是迭代器,表示一个p::value_type类型值的范围;
il是值的花括号列表;
只插入关键字不在set中的元素
返回类型为void
对于multiset会插入范围内的所有元素,不检查key是否相等
p.insert(b, v)
p.emplace(args)
b是迭代器,表示从哪里插入元素v;
返回一个迭代器,指向具有指定关键字的元素 。
set<int> setInt;
setInt.insert(3); setInt.insert(1);setInt.insert(5);setInt.insert(2);
for(set<int>::iterator it=setInt.begin(); it!=setInt.end(); ++it)
{
int iItem = *it;
cout << iItem; //或直接使用 cout << *it
}
//顺序输出 1 2 3 5

6. set删除

set.clear(); //清除所有元素
set.erase(pos); //删除 pos 迭代器所指的元素,返回下一个元素的迭代器。
set.erase(beg,end); //删除区间[beg,end)的所有元素,返回下一个元素的迭代器。
set.erase(elem); //删除容器中值为 elem 的元素。

7. set的查找操作

set.find(elem); //查找 elem 元素,返回指向 elem 元素的迭代器
set.count(elem); //返回容器中值为 elem 的元素个数。对 set 来说,要么是 0,要么是 1。对 multiset 来说,值可能大于 1
set.lower_bound(elem); //返回第一个>=elem 元素的迭代器
set.upper_bound(elem); // 返回第一个>elem 元素的迭代器
set.equal_range(elem); //返回一个迭代器pair,表示关键字等于elem的元素的范围。若k不存在,pair的两个成员均等于set.end()
C++中,`set` `multiset` 都属于关联容器,存储的元素都会根据元素的值自动进行排序。但两者存在以下区别: ### 元素唯一性 - `set` 容器中不允许有重复的元素,当插入重复元素时,插入操作会失败。例如以下代码: ```cpp #include <iostream> #include <set> using namespace std; void test01() { set<int> s; pair<set<int>::iterator, bool> ret = s.insert(10); if (ret.second) { cout << "第一次插入成功" << endl; } else { cout << "第一次插入失败" << endl; } ret = s.insert(10); if (ret.second) { cout << "第二次插入成功" << endl; } else { cout << "第二次插入失败" << endl; } } int main() { test01(); return 0; } ``` 该代码展示了 `set` 插入重复元素时,第二次插入会失败[^1]。 - `multiset` 容器允许有重复的元素,插入重复元素会成功。如下代码: ```cpp #include <iostream> #include <set> using namespace std; void testMultiset() { multiset<int> ms; ms.insert(10); ms.insert(10); ms.insert(10); ms.insert(10); for (multiset<int>::iterator it = ms.begin(); it != ms.end(); it++) { cout << *it << " "; } cout << endl; } int main() { testMultiset(); return 0; } ``` 该代码展示了 `multiset` 可以多次插入相同元素,且能正常存储并遍历输出[^1]。 ### 容器大小 由于 `set` 不允许重复元素,而 `multiset` 允许,所以对于包含重复元素的初始化序列,两者的大小可能不同。例如: ```cpp #include <string> #include <iostream> #include <set> #include <vector> using namespace std; int main() { vector<int> ivec; for(int i = 0; i!= 10;++i) { ivec.push_back(i); ivec.push_back(i); } set<int> iset(ivec.begin(),ivec.end()); multiset<int> miset(ivec.begin(),ivec.end()); cout << iset.size() << endl; cout << miset.size() << endl; cout << ivec.size() << endl; return 0; } ``` 此代码中,`iset` 的大小为 10,`miset` 的大小为 20,因为 `iset` 会去重,而 `miset` 保留所有元素[^2]。 ### 插入返回值 - `set` 的 `insert` 方法返回一个 `pair`,其中 `pair` 的 `second` 成员是一个布尔值,表示插入是否成功。 - `multiset` 的 `insert` 方法返回一个迭代器,指向新插入元素的位置,因为 `multiset` 插入总是成功,所以不需要返回布尔值表示插入结果。 ### 查找元素 - 在 `set` 中查找元素,若找到,返回指向该元素的迭代器;若未找到,返回 `end()` 迭代器。 - 在 `multiset` 中查找元素,若找到,返回指向该元素的迭代器;由于可能存在多个相同元素,`multiset` 还提供了 `count` 方法用于统计某个元素的出现次数。 ### 元素删除 - 在 `set` 中删除元素,若元素存在则删除并返回 1,若不存在则返回 0。 - 在 `multiset` 中删除元素,会删除所有与指定值相等的元素,并返回被删除元素的数量。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值