C++——set 和 multiset

2023-11-11

 


 
 

  Set 和 multiset 会根据特定的排序准则,自动将元素排序。两者不同之处在于 multiset 允许元素重复而 set 不允许。
set和multiset
set 和 multiset 包含在头文件中:

#include <set>

在这个头文件中,上述两个类型都被定义为命名空间 std 内的 class template:

namespace std {
	template <typename T,
				typename Compare = less<T>,
				typename Allocator = allocator<T> >
			class set;
	
	template <typename T,
				typename Compare = less<T>,
				typename Allocator = allocator<T> >
			class multiset;
}

只要是可依据某排序准则被比较(所谓 comparable )的任意类型 T 都可以成为 set 或 multiset 的元素类型。可有可无的第二个 template 实参用来定义排序准则。如果没有传入某个排序准则,就采用默认准则 less——这是个函数对象,以 operator < 对元素进行比较。可有可无的第三实参用来定义内存模型。默认的内存模型是 allocator,由 C++ 标准库提供。
  “排序准则”,必须定义 strict weak ordering,其意义如下:

  1. 必须是非对称的
    对 operator < 而言,如果 x < y 为 true,则 y < x 为 false。
    对判断式(predicate)op() 而言,如果 op(x, y) 为 true,则 op(y, x) 为 false。
  2. 必须是可传递的
    对 operator < 而言,如果 x < y 为 true 且 y < z 为 true,则 x < z 为 true。
    对判断式 op() 而言,如果 op(x, y) 为 true 且 op(y, z) 为 true,则 op(x, z) 为 true。
  3. 必须是非自反的
    对 operator < 而言,x < x 永远为 false。
    对判断式 op() 而言,op(x, x) 永远为 false。
  4. 必须有等效传递性。大体意义是:如果 a 等于 b 且 b 等于 c,那么 a 必然等于 c。
    这意味着对于操作符 <,若 !(a<b) && !(b<a) 为 true 且 !(b<c) && !(c<b) 为 true,那么 !(a<c) && ! (c<a) 亦为 true。
    这也意味着对于判断式 op(),若 op(a, b)、 op(b, a)、 op(b, c)和 op(c, b) 都为 false,那么 op(a, c)和 op(c, a) 为 false。

  注意,这意味着你必须区分 less 和 equal。一个像 operator <= 这样的准则并不满足这个条件。
  根据这些性质,排序准则也被用来检查等效性。也就是说,两个元素如果没有任何一个小于另一个(或如果 op(x, y) 和 op(y, x) 都取得 false ),则它们被视为重复。
  Multiset 的等效元素的次序是随机但稳定的。因此 C++11 保证安插和抹除动作都会保存等效元素的相对次序。

 
 

 
 

 
 

结构

  和所有标准的关联式容器类似,set 和 multiset 通常以平衡二叉树(如下图)完成——C++ standard 并未明定,但由 set和 multiset 各项操作的复杂度可以得出这个结论——事实上,set 和 multiset 通常以红黑树实现。红黑树在改变元素数量和元素搜寻方面都很出色,它保证节点安插时最多只会做两个重新链接动作,而且到达某一元素的最长路径的深度,至多只是最短路径的深度的两倍。
set和multiset内部结构
  自动排序的主要优点在于令二叉树于查找元素时拥有良好效能。其查找函数具有对数复杂度。在拥有 1000 个元素的 set 或 multiset 中查找元素,二叉树查找动作(由成员函数执行)的平均时间为线性查找(由STL 算法执行)的 1/50。。
  但是,自动排序造成 set 和 multiset 的一个重要限制:你不能直接改变元素值,因为这样会打乱原本正确的顺序。
因此,要改变元素值,必须先删除旧元素,再插入新元素。以下接口反映了这种行为:

  • Set 和 multiset 不提供任何操作函数可以直接访问元素。
  • 通过迭代器进行元素间接访问,有一个限制:从迭代器的角度看,元素值是常量。

 
 

 
 

 
 

构造

操作 描述
set c Default 构造函数,建立一个空 set / multiset,不含任何元素
set c(op) 建立一个空 set / multiset,以 op 为排序准则
set c(c2) Copy 构造函数,为相同类型之另一个 set / multiset 建立一份拷贝,所有元素均被复制
set c = c2 Copy 构造函数,为相同类型之另一个 set / multiset 建立一份拷贝,所有元素均被复制
set c(rv) Move 构造函数,建立一个新的 set / multiset,有相同类型,取 rvalue rv 的内容(始自C++11)
set c = rv Move 构造函数,建立一个新的 set / multiset,有相同类型,取 rvalue rv 的内容(始自C++11)
set c(beg, end) 以区间 [beg, end) 内的元素为初值,建立一个 set / multiset
set c(beg, end, op) 以区间 [beg, end) 内的元素为初值,并以 op 为排序i准则,建立一个 set / multiset
set c(initlist) 建立一个 set / multiset,以初值列 initlist 的元素为初值(始自C++11)
set c = initlist 建立一个 set / multiset,以初值列 initlist 的元素为初值(始自C++11)
c.~set() 销毁所有元素,释放内存
其中set可为下列形式:
set 描述
set< Elem > 一个 set,以 less<> (operator <) 为排序准则
set< Elem, Op > 一个 set,以 Op 为排序准则
multiset< Elem > 一个 multiset,以 less<> (operator <) 为排序准则
multiset< Elem, Op > 一个 multiset,以 Op 为排序准则
#include <iostream>
#include <set>
using namespace std;

struct op{
	bool operator() (const int& a, const int& b) const{
		return a > b;
	}
};

int main(){
	int a[] = {1, 2, 3, 4, 5, 6, 7, 8};
	set<int> c(a, a + 6);
	set<int> c1;
	set<int> c2(op);
	set<int> c3(c);
	set<int> c4 = c;
	
	
	printf("c: ");
	for(set<int>::iterator i = c.begin(); i != c.end(); i ++)
		cout << *i << " ";
	printf("\n");
	
	printf("c3: ");
	for(set<int>::iterator i = c3.begin(); i != c3.end(); i ++)
		cout << *i << " ";
	printf("\n");
	
	printf("c4: ");
	for(set<int>::iterator i = c4.begin(); i != c4.end(); i ++)
		cout << *i << " ";
	printf("\n");
	return 0;
}

运行结果

 
 

 
 

 
 

非更易型操作

操作 描述
c.key_comp() 返回“比较准则”
c.value_comp() 返回针对 value 的“比较准则”(和 key_comp() 相同)
c.empty() 返回是否容器为空(相当于 size()==0 但也许较快)
c.size() 返回目前的元素个数
c.max_size() 返回元素个数之最大可能量
c1 == c2 返回 c1 是否等于 c2(对每个元素调用==)
c1 != c2 返回 c1 是否不等于 c2(相当于 !(c1 == c2) )
c1 < c2 返回 c1 是否小于 c2
c1 > c2 返回 c1 是否大于 c2(相当于 c2 < c1)
c1 <= c2 返回 c1 是否小于等于 c2(相当于 !(c2 < c1) )
c1 >= c2 返回 c1 是否大于等于 c2(相当于 !(c1 < c2) )
#include <iostream>
#include <set>
using namespace std;

struct op{
	bool operator() (const int& a, const int& b) const{
		return a > b;
	}
};

int main(){
	int a[] = {1, 2, 3, 4, 5, 6, 7, 8};
	set<int, op> c(a, a + 6);
	set<int, op> c1 = c;
	set<int, op> c2(a + 1, a + 7);
	
	printf("key_comp(): %s\n", c.key_comp()(1, 2) ? "true" : "false");//1>2: false
	printf("key_comp(): %s\n", c.key_comp()(2, 1) ? "true" : "false");//2>1: true
	printf("value_comp(): %s\n", c.value_comp()(1, 2) ? "true" : "false");//1>2: false
	printf("value_comp(): %s\n", c.value_comp()(2, 1) ? "true" : "false");//2>1: true
	printf("empty(): %s\n", c.empty() ? "true" : "false");
	printf("size(): %d\n", c.size());
	printf("max_size(): %lld\n", c.max_size());
	printf("c1 == c: %s\n", c1 == c ? "true" : "false");
	printf("c1 != c2: %s\n", c1 != c2 ? "true" : "false");
	printf("c1 < c: %s\n", c1 < c ? "true" : "false");
	printf("c1 > c2: %s\n", c1 > c2 ? "true" : "false");
	printf("c1 <= c: %s\n", c1 <= c ? "true" : "false");
	printf("c1 >= c2: %s\n", c1 >= c2 ? "true" : "false");
	return 0;
}

运行结果

 
 

 
 

 
 

查找操作

操作 描述
c.count(val) 返回“元素值为 val ”的元素个数
c.find(val) 返回“元素值为 val ”的第一个元素,如果找不到就返回 end()
c.lower_bound(val) 返回 val 的第一个可安插位置,也就是“元素值 >= val ”的第一个元素位置
c.upper_bound(val) 返回 val 的最后一个可安插位置,也就是“元素值 > val ”的第一个元素位置
c.equal_range(val) 返回 val 可被安插的第一个位置和最后一个位置,也就是“元素值 == val ”的元素区间。将 lower_bound() 和 upper_bound() 的返回值做成一个 pair 返回。
如果 lower_bound() 或“ equal_range() 的 first 值”等于“ equal_range() 的 second 值”或 upper_bound(),则此 set 或 multiset 内不存在同值元素。
#include <iostream>
#include <set>
using namespace std;

int main(){
	set<int> c;
	c.insert(1);
	c.insert(2);
	c.insert(3);
	c.insert(4);
	c.insert(5);
	c.insert(6);
	
	printf("count(): %d\n", c.count(2));
	printf("find(): %d\n", c.find(3));
	cout << "lower_bound(3): " << *c.lower_bound(3) << endl;
	cout << "upper_bound(3): " << *c.upper_bound(3) << endl;
	cout << "equal_range(3): " <<*c.equal_range(3).first <<
								*c.equal_range(3).second << endl;
	cout <<endl;
	cout << "lower_bound(5): " << *c.lower_bound(5) << endl;
	cout << "upper_bound(5): " << *c.upper_bound(5) << endl;
	cout << "equal_range(5):" << *c.equal_range(5).first <<
									*c.equal_range(5).second << endl;
	return 0;
}

运行结果

 
 

 
 

 
 

赋值操作

操作 描述
c = c2 将 c2 的全部元素赋值给 c
c = rv 将 rvalue rv 的所有元素以 move assign 方式给予 c (始自C++11)
c = initlist 将初值列 initlist 的所有元素赋值给 c (始自C++11)
c1.swap(c2) 置换 c1 和 c2 的数据
swap(c1, c2) 置换 c1 和 c2 的数据
#include <iostream>
#include <set>
using namespace std;

int main(){
	int a[] = {1, 2, 3, 4, 5, 6, 7, 8};
	set<int> c(a, a + 6);
	set<int> c1 = c;
	set<int> c2 = {2, 3, 4, 5, 6, 7};
	
	printf("c1: ");
	for(set<int>::iterator i = c1.begin(); i != c1.end(); i ++)
		cout << *i << " ";
	printf("\n");
	
	printf("c2: ");
	for(set<int>::iterator i = c2.begin(); i != c2.end(); i ++)
		cout << *i << " ";
	printf("\n");
	
	swap(c1, c2);
	printf("\n交换c1和c2!\n");
	printf("c1: ");
	for(set<int>::iterator i = c1.begin(); i != c1.end(); i ++)
		cout << *i << " ";
	printf("\n");
	
	return 0;
}

运行截图

 
 

 
 

 
 

迭代器相关操作

操作 描述
c.begin() 返回一个 bidirectional iterator 指向第一元素
c.end() 返回一个 bidirectional iterator 指向最末元素的下一位置
c.cbegin() 返回一个 const bidirectional iterator 指向第一元素(始自C++11)
c.cend() 返回一个 const bidirectional iterator 指向最末元素的下一位置(始自C++11)
c.rbegin() 返回一个反向的 (reverse) iterator 指向反向迭代的第一元素
c.rend() 返回一个反向的 (reverse) iterator 指向反向迭代的最末元素的下一位置
c.crbegin() 返回一个 const reverse iterator 指向反向迭代的第一元素(始自C++11)
c.crend() 返回一个 const reverse iterator 指向反向迭代的最未元素的下一位置(始自C++11)
#include <iostream>
#include <set>
using namespace std;

int main(){
	int a[] = {1, 2, 3, 4, 5, 6, 7, 8};
	set<int> c(a, a + 6);
	set<int> c1 = c;
	
	printf("利用begin()和end()遍历set(c1): ");
	for(set<int>::iterator i = c1.begin(); i != c1.end(); i ++)
		cout << *i << " ";
	printf("\n");
	
	printf("利用rbegin()和rend()遍历set(c1): ");
	for(set<int>::reverse_iterator i = c1.rbegin(); i != c1.rend(); i ++)
		cout << *i << " ";
	printf("\n");
	return 0;
}

运行截图

 
 

 
 

 
 

插入和移除操作

操作 描述
c.insert(val) 安插一个 val 拷贝,返回新元素位置,不论是否成功——对 set 而言
c.insert(pos, val) 安插一个 val 拷贝,返回新元素位置( pos 是个提示,指出安插动作的查找起点。若提示恰当可加快速度)
c.insert(beg, end) 将区间 [beg, end) 内所有元素的拷贝安插到 c (无返回值)
c.insert(initlist) 安插初值列 initlist 内所有元素的一份拷贝(无返回值;始自C++11)
c.emplace(args . . .) 安插一个以 args 为初值的元素,并返回新元素的位置,不论是否成功——对 set 而言(始自C++11)
c.emplace_hint(pos , args . . .) 安插一个以 args 为初值的元素,并返回新元素的位置( pos 是个提示,指出安插动作的查找起点。若提示恰当可加快速度)
c.erase(val) 移除“与 val 相等”的所有元素,返回被移除的元素个数
c.erase(pos) 移除 iterator 位置 pos 上的元素,无返回值
c.erase(beg, end) 移除区间 [beg, end) 内的所有元素,无返回值
c.clear() 移除所有元素,将容器清空

Set 提供如下接口:

pair<iterator, bool> insert(const value_type& val);
iterator 			 insert(const_iterator posHint, const value_type& val);
template <typename... Args> pair<iterator, bool> emplace(Args&&... args);
template <typename... Args> iterator emplace_hint(const_iterator posHint, Args&&... args);

Multiset 提供如下接口:

iterator insert(const value_type& val);
iterator insert(const_iterator posHint, const value_type& val);
template <typename... Args> iterator emplace(Args&&... args);
template <typename... Args> iterator emplace_hint(const_iterator posHint, Args&&... args);

返回类型之所以不相同,原因是: multiset 允许元素重复而 set 不允许。因此,如果将某元素安插至 set 内,而该 set 已经内含同值元素,安插动作将告失败。所以 set 的返回类型是以 pair 组织起来的两个值:

  1. pair 结构中的 second 成员表示安插是否成功。
  2. pair 结构中的 first 成员表示新元素的位置,或现存的同值元素的位置。

其他任何情况下,此函数都返回新元素的位置(如果 set 已经内含同值元素,则返回同值元素的位置)。

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

int main(){
	int a[] = {1, 2, 3, 4, 5, 6, 7, 8};
	set<int> c(a, a + 6);
	set<int> c1;
	
	pair<set<int>::iterator, bool> p = c.insert(7);
	printf("%s%d: ", p.second ? "成功插入" : "插入失败", *p.first);
	for(set<int>::iterator i = c.begin(); i != c.end(); i ++)
		cout << *i << " ";
	printf("\n");
	
	set<int>::iterator p1 = c.insert(c.end(), 8);
	printf("成功插入%d: ", *p1);
	for(set<int>::iterator i = c.begin(); i != c.end(); i ++)
		cout << *i << " ";
	printf("\n");
	
	c1.insert(a, a + 6);
	printf("c1插入a到a+6的数据: ");
	for(set<int>::iterator i = c1.begin(); i != c1.end(); i ++)
		cout << *i << " ";
	printf("\n\n");
	
	p = c1.emplace(7);
	printf("%s%d: ", p.second ? "成功插入" : "插入失败", *p.first);
	for(set<int>::iterator i = c1.begin(); i != c1.end(); i ++)
		cout << *i << " ";
	printf("\n");
	
	p1 = c1.emplace_hint(c1.end(), 8);
	printf("成功插入%d: ", *p1);
	for(set<int>::iterator i = c1.begin(); i != c1.end(); i ++)
		cout << *i << " ";
	printf("\n\n");
	
	int cnt = c.erase(4);
	printf("成功移除%d个4: ", cnt);
	for(set<int>::iterator i = c.begin(); i != c.end(); i ++)
		cout << *i << " ";
	printf("\n");
	
	c.erase(c.begin());
	printf("成功移除首位元素: ");
	for(set<int>::iterator i = c.begin(); i != c.end(); i ++)
		cout << *i << " ";
	printf("\n");
	
	c.erase(c.begin(), c.end());
	printf("成功移除所有元素: ");
	for(set<int>::iterator i = c.begin(); i != c.end(); i ++)
		cout << *i << " ";
	printf("\n");
	
	c1.clear();
	printf("成功清除所有元素: ");
	for(set<int>::iterator i = c1.begin(); i != c1.end(); i ++)
		cout << *i << " ";
	printf("\n");
	return 0;
}

运行结果

 
 

 
 

 
 

自定义排序准则

利用set内部默认的compare函数,可以将整数从小到大排序。

可以通过定义结构体(或类),并在其中重载()运算符,来自定义排序函数。然后,在定义set的时候,将结构体加入其中例如如下代码中的 set<int, op> 或 set< int > c(op)。
规则代码如下:

//结构体
struct op{
	bool operator() (const int& a, const int& b) const{
		return a > b;
	}
};
//类
class op1{
public:
	bool operator() (const int& a, const int& b) const{
		return a > b;
	}
};

看一个示例:

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

struct op{
	bool operator() (const int& a, const int& b) const{
		return a > b;
	}
};

class op1{
public:
	bool operator() (const int& a, const int& b) const{
		return a > b;
	}
};

int main(){
	int a[] = {1, 2, 3, 4, 5, 6, 7, 8};
	set<int> c1(a, a + 6);
	set<int, op> c2(a, a + 6);
	set<int, op1> c3(a, a + 6);
	
	printf("默认排序准则c1: ");
	for(set<int>::iterator i = c1.begin(); i != c1.end(); i ++)
		cout << *i << " ";
	printf("\n");
	
	printf("自定义排序准则c2: ");
	for(set<int>::iterator i = c2.begin(); i != c2.end(); i ++)
		cout << *i << " ";
	printf("\n");
	
	printf("自定义排序准则c3: ");
	for(set<int>::iterator i = c3.begin(); i != c3.end(); i ++)
		cout << *i << " ";
	printf("\n");
	return 0;
}

运行结果
 
 

 
 
在自定义结构体中重载< 也可以实现默认排序,示例代码如下:

struct Student{
	string id;
	string college;
	int age;
	
	bool operator <(const Student& a) const{
		if(college != a.college)
			return college < a.college;
		else if(id != a.id)
			return id < a.id;
		else
			return age < a.age;
			
	}
};
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++——set 和 multiset 的相关文章

随机推荐

  • Python制作一款简单的乒乓球小游戏

    开发工具 Python版本 3 6 4 相关模块 pygame模块 以及一些Python自带的模块 相关文件 关注公众号 Python学习指南 回复 乒乓球 即可获取 环境搭建 pip安装需要的相关模块即可 原理简介 游戏规则 操作 玩家1
  • AWS SAA-C03 #49

    A company stores call transcript files on a monthly basis Users access the files randomly within 1 year of the call but
  • 虚拟机磁盘扩容

    1 前言 现在做开发时 虚拟机的使用很多 经常遇到这样的问题 当初创建虚拟机的时候开辟的磁盘空间比较小 随着虚拟机安装的软件越来越多所占的空间也越来越大 导致虚拟机的磁盘空间越来越少 甚至不够用 此时我们便可以对虚拟机的磁盘大小进行扩容 简
  • 中秋闲鱼卖货,月入过万的新玩法?

    中秋节越来越近了 都开始忙着走亲串友 人情社会关系要多走动 虽然大家都在忙着搞钱 但是逢年过节要停下脚步享受美好生活 月圆中秋思念满满每逢佳节倍思亲 在异国他乡的朋友因疫情不能回家团聚 但现在移动互联网给人们生活带来太多便捷 打电话语音视频
  • 获得用户输入的一个字符串,输出其中字符a的出现次数

    task19 获得用户输入的一个字符串 输出其中字符a的出现次数 name wangzilu date 2020 2 19 task 获得用户输入的一个字符串 输出其中字符a的出现次数 first way x str input pleas
  • shell 重定向到文件

    首先明确基本 gt dev null 输出到空设备 表示丢掉输出信息 2 gt 1 将输出到标准错误的信息输出到标准输出设备 通常是屏幕 有3个默认的i o 0 是标准输入 一般是键盘 1 是标准输出 一般是屏幕了 2 是标准错误 有时候屏
  • 编程笔记:Windows Forms in C#

    1 画线时遇到的奇怪问题 以下摘取部分代码 Graphics g null g CreateGraphics private void Form1 MouseMove object sender MouseEventArgs e 下面三行代
  • 第七章、并发编程实战项目

    一 并发任务执行框架 架构师是什么 在一个软件项目开发过程中 将客户的需求转换为规范的开发计划及文本 并制定这个项目的总体架构 指导整个开发团队完成这个计划的那个人 就是 架构师 一般是一个项目里的最资深的专业技术人员 可以说架构师首先一定
  • 【SDOI2016】数字配对【建立二分图+费用流求方案数】

    题目链接 首先 我们可以看一下这个推导过程 如果 那么 对于 就一定不是质数 一定是它的一个因子 于是可以看出 这一定是一幅二分图 于是 可以根据二分图的性质来确定了每个点的属于S边还是T边了 include
  • 《深入理解mybatis原理》 MyBatis事务管理机制

    版权声明 本文为博主原创文章 未经博主允许不得转载 https blog csdn net u010349169 article details 37992171 MyBatis作为Java语言的数据库框架 对数据库的事务管理是其非常重要的
  • 在手机端点击input框不弹出输入法的方法

    1 使用CSS样式 input pointer events none 2 使用事件阻止 input onmousedown function e e preventDefault 这样不仅会阻止键盘 同时 input 会失去光标跟随 如果
  • 通俗易懂的LSTM

    目录 一 LSTM的基础知识 1 长依赖的问题 2 LSTM的核心 3 LSTM的门结构 4 LSTM门结构的作用 5 LSTM的变体 GRU 二 LSTM的补充知识 1 LSTM缓解梯度消失的原因 一 LSTM的基础知识 1 长依赖的问题
  • Python OpenCV 解决人脸识别报错cascade.detectMultiScale error

    Authored by Monana Contact me via serena9636 163 com 环境 Python2 7 OpenCV3 1 0 Win 64bit 我想在OpenCV中实现一段如下的很简单的人脸识别代码 这也是在
  • vsCode返回上一步

    vsCode返回上一步 windows Alt 上下左右的左箭头 Linux Ctrl Alt 减号
  • 图像信噪比的理解

    图像的信噪比和图像的清晰度一样 都是衡量图像质量高低的重要指标 图像的信噪比是指视频信号的大小与噪波信号大小的比值 其公式为 S N 信噪比 20 log 信号 噪声 dB 信噪比大 图像画面就干净 看不到什么噪波干扰 表现为 颗粒 和 雪
  • 使用VMware完成KVM虚拟化实验并运行Centos

    本次实验在VMware中的Ubuntu18内安装KVM并运行centos 首先 在VMware下开启虚拟化 更新软件索引 apt get update 安装依赖 apt get install qemu kvm qemu virt mana
  • js验证姓名,包括少数民族名字中的·,后你哦·就两节课了

    姓名验证 u4E00 u9FA5 uf900 ufa2d s 2 20 亲测
  • Outlook VBA自动处理邮件

    需求描述 公司里面每天都会有很多邮件 三分之一都是不需要看的 Outlook的过滤功能不错 都可以处理掉 还有些邮件 根据正文或者附件做一下处理自动转发出去就行了 于是上网搜集了一些资料 写个了小程序 共享一下 以后可以参考 也希望对大家有
  • Linux系列一 VMware 中 Fedora系统的安装与网络配置

    之前一篇文章 简单地总结了自己的Linux假期培训课程 因为自己也打算开始学习Linux 所以就在这里写点东西 记录自己的学习历程 如果也能给大家带去一点帮助的话 甚是欣慰 能力时间有限 难免有疏漏的地方 还希望大家多多批评指正 本篇文章的
  • C++——set 和 multiset

    文章目录 结构 构造 非更易型操作 查找操作 赋值操作 迭代器相关操作 插入和移除操作 自定义排序准则 Set 和 multiset 会根据特定的排序准则 自动将元素排序 两者不同之处在于 multiset 允许元素重复而 set 不允许