C++ set&mulitset 与 仿函数(函数对象)

进阶C++__STL__set/ multiset和map/ multimap使用方法 一、关联式容器 二、键值对 三、树形结构的关联式容器 set/ multiset 容器 set基本概念 set构造和赋值 set大小和交换 set插入和删除 set查找和统计 set和multiset区别 set / multiset总结 pair对组创建 set容器排序 内置类型指定排序规则 自定义数据类型指定排序规则 map/ multimap容器 map基本概念 map构造和赋值 map大小和交换 map插入和删除 map查找和统计 map容器排序 map 阅读详情

在学习仿函数(函数对象)前,我们得先了解set 与 mulitset 的底层排序原理!

set 与 mulitset 也是一个容器,是一个集合容器。
而set存储的元素始终都是唯一的,而mulitset可以存储相同的元素。

这篇文章就以set为例子说明,mulitset和set的用法完全一样!

如果不懂得set 与 mulitest 容器的,可以点下面链接去学习:
https://blog.youkuaiyun.com/cpp_learner/article/details/104751672


set 和 mulitset 都是顺序存储元素的。

在看例子前,先了解一下,set 和 mulitset 都有两个函数来提同排序:less 和 greater

其中less是顺序排序,而greater是逆序排序!

下面请看一个例子:

#include <iostream>
#include <Windows.h>
#include <set>
#include <functional>
#include <algorithm>

using namespace std;

int main(void) {
	set<int> s1;	// 等同于默认值:set<int, less<int>> s1;
	//set<int, less<int>> s1;	// 正序排序

	for (int i = 0; i < 10; i++) {
		s1.insert(10 - i);
	}

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




	set<int, greater<int>> s3;	// 倒序排序

	for (int i = 0; i < 10; i++) {
		s3.insert(i);
	}

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

	system("pause");
	return 0;
}

运行截图:
在这里插入图片描述

代码中,我们逆序将1 - 10 存储进s1中,将0 - 9 正序存出进s3中,但是数出来的结果却是,s1是正序输出,而s3是逆序输出!

有这样的结果都是less 和 greater 这两个函数搞的鬼。

这两个函数都是在头文件#include <functional>中。

我们看一下在这两个函数的底层具体代码:
在这里插入图片描述

我们可以知道,它底层实现原理实际上就是函数模板和重载了()运算符。
比如:
less中,假如比较 3 和 4, 那么就会返回true,3就会排在4的前面,形成顺序排序。
greater中,也比较3 和 4,那么就会返回false,3就会排在4的后面,形成逆序排序。


好了,知道了这些,我们再来假如:容器不可能一直都会存储int类型的元素,也会存储其他类型的元素,比如类的对象!
那么存储对象时,他是如何比较排序的呢?

我们先看代码:

#include <iostream>
#include <Windows.h>
#include <set>
#include <functional>
#include <algorithm>

using namespace std;

class Student {
public:
	Student(int age, const char* name) {
		this->age = age;

		this->name = new char[strlen(name) + 1];
		strcpy_s(this->name, strlen(name) + 1, name);
	}

	~Student() {
		if (name) {
			delete[] name;
			name = NULL;
			age = 0;
		}
	}

	// 拷贝构造函数
	Student(const Student& student) {
		this->age = student.age;

		this->name = new char[strlen(student.name) + 1];
		strcpy_s(this->name, strlen(student.name) + 1, student.name);
	}

	int getAge() const {
		return age;
	}

	char* getName() const {
		return name;
	}

private:
	int age;
	char* name;
};


int main(void) {
	set<Student> s1;	// 等同于默认值:set<Student, less<Student>> s1;

	// 将两个临时对象插入容器中
	s1.insert(Student(20, "张三"));
	s1.insert(Student(22, "李四"));

	for (set<Student>::iterator it = s1.begin(); it != s1.end(); it++) {
		cout << "年龄:" << it->getAge() << " 姓名:" << it->getName() << endl;
	}

	system("pause");
	return 0;
}

还是和刚才差不多的代码,只是多定义一个Student类。
我们把对象存入容器中,然后在打印出来,看看他是如何排序的!

运行后:
在这里插入图片描述
居然运行报错了,编译不通过啊,这是怎么回事啊???

大家请看第一行画红线部分,那些标明了错误的原因!

是 “<" 运算符的问题。

我们再看一下刚才底层的代码:(以less为例说明)
在这里插入图片描述

他是一个模板哎,当模板替换为类时,对象是不能直接比较的,所以才会编译不通过。
解决办法就是:当要使用less时,重载<运算符。当要使用greater,重载>运算符!
我这里就两个都写下来!

#include <iostream>
#include <Windows.h>
#include <set>
#include <functional>
#include <algorithm>

using namespace std;

class Student {
public:
	Student(int age, const char* name) {
		this->age = age;

		this->name = new char[strlen(name) + 1];
		strcpy_s(this->name, strlen(name) + 1, name);
	}

	~Student() {
		if (name) {
			delete[] name;
			name = NULL;
			age = 0;
		}
	}

	// 拷贝构造函数
	Student(const Student& student) {
		this->age = student.age;

		this->name = new char[strlen(student.name) + 1];
		strcpy_s(this->name, strlen(student.name) + 1, student.name);
	}

	int getAge() const {
		return age;
	}

	char* getName() const {
		return name;
	}

	// < 运算符重载
	bool operator<(const Student student) const {
		return this->age < student.age;
	}

	// > 运算符重载
	bool operator>(const Student student) const {
		return this->age > student.age;
	}

private:
	int age;
	char* name;
};


int main(void) {
	set<Student> s1;	// 等同于默认值:set<Student, less<Student>> s1;

	// 将两个临时对象插入容器中
	s1.insert(Student(20, "张三"));
	s1.insert(Student(22, "李四"));

	for (set<Student>::iterator it = s1.begin(); it != s1.end(); it++) {
		cout << "年龄:" << it->getAge() << " 姓名:" << it->getName() << endl;
	}

	system("pause");
	return 0;
}

运行截图:
在这里插入图片描述

完美运行!!!


好了,有了以上的铺垫,我们可以来讲 仿函数(函数对象) 了

仿函数(函数对象)

仿函数概念

  1. 尽管函数指针被广泛用于实现函数回调,但C++还提供了一个重要的实现回调函数的方法,那就是函数对象。
  2. functor,翻译成函数对象,伪函数,它是是重载了“()”操作符的普通类对象。从语法上讲,它与普通函数行为类似。
  3. functional头文件中包含的 greater<>与less<>就是函数对象。

下面举出greater 和 less的简易实现原理。

struct greater
{
bool operator() (const int& iLeft, const int& iRight)
{
return (iLeft>iRight);
}
}

struct less
{
bool operator() (const int& iLeft, const int& iRight)
{
return (iLeft<iRight);
}
}

set/setmulti容器就是调用函数对象的operator()方法去比较两个值的大小。


运用仿函数我们可以自行调用自己写的函数对象来排序set 和 mulitset.

例如:
以less为例:

// 仿函数(函数对象)
class FunStudent {
public:
	bool operator()(const Student& s1, const Student& s2) const {
		return s1.getAge() < s2.getAge();
	}
};

把他复制到上面的代码中:

#include <iostream>
#include <Windows.h>
#include <set>
#include <functional>
#include <algorithm>

using namespace std;

class Student {
public:
	Student(int age, const char* name) {
		this->age = age;

		this->name = new char[strlen(name) + 1];
		strcpy_s(this->name, strlen(name) + 1, name);
	}

	~Student() {
		if (name) {
			delete[] name;
			name = NULL;
			age = 0;
		}
	}

	// 拷贝构造函数
	Student(const Student& student) {
		this->age = student.age;

		this->name = new char[strlen(student.name) + 1];
		strcpy_s(this->name, strlen(student.name) + 1, student.name);
	}

	int getAge() const {
		return age;
	}

	char* getName() const {
		return name;
	}

	// < 运算符重载
	bool operator<(const Student student) const {
		return this->age < student.age;
	}

	// > 运算符重载
	bool operator>(const Student student) const {
		return this->age > student.age;
	}

private:
	int age;
	char* name;
};


// 仿函数(函数对象)
class FunStudent {
public:
	bool operator()(const Student& s1, const Student& s2) const {
		return s1.getAge() < s2.getAge();
	}
};


int main(void) {
	set<Student, FunStudent> s1;	// 等同于默认值:set<Student, less<Student>> s1;


	Student stu1(20, "张三");
	Student stu2(22, "李四");

	// 函数对象(仿函数)可以像函数一样直接调用
	//FunStudent funStudent;
	//funStudent(stu1, stu2);


	s1.insert(stu1);
	s1.insert(stu2);

	for (set<Student, FunStudent>::iterator it = s1.begin(); it != s1.end(); it++) {
		cout << "年龄:" << it->getAge() << " 姓名:" << it->getName() << endl;
	}


	system("pause");
	return 0;
}

定义仿函数后,就可以使用它来代替less/greater了。
例如:set<Student, FunStudent> s1;

运行截图:
在这里插入图片描述

也是完美运行!!!


也许会有人问,自己定义的仿函数和上面的输出结果没有什么变化啊,那我还搞那么多代码干嘛??

有这样的疑问时正常的,其实他的用处大着呢!

比如,他是一个类,我们可以随意的改写它,使他能更好的运行!
举一个例子:

// 仿函数(函数对象)
class FunStudent {
public:
	bool operator()(const Student& s1, const Student& s2) const {
		ret = s1.getAge() < s2.getAge();
		return ret;
	}

	bool getRet() const {
		return ret;
	}
private:
	bool ret;
};

你可以这样获取他的返回值!
还有其他很多使用的,可以自己根据具体请看进行编写代码!!


到了这里,仿函数也讲完了,总的来说,仿函数也还是比较实用的!

C++中的Multiset容器及其使用方法 上述定义语句创建了一个不包含任何元素的multiset容器。这个容器将包含5个整数元素,分别是4、2、1、5和3。 阅读详情

相关推荐

PubMedBERT:生物医学NLP中的垂直领域预训练实践与性能突破

本文深入探讨了PubMedBERT在生物医学NLP领域的应用与性能突破。作为专为生物医学文本设计的预训练模型,PubMedBERT通过全词掩码策略和BLURB基准测试,显著提升了命名实体识别、关系抽取等任务的准确率。文章还提供了PubMedBERT的实战应用案例和代码示例,展示了其在医学文献检索和电子病历结构化中的卓越表现。

kite3的博客 283

【C++自学笔记】STL-详细解析set、mulitset(关联式容器)

一、set和multiset 的介绍和使用 1、set 1、set的介绍 set是按照一定次序存储元素的容器,在set 中,元素的 value也标识它(value就是key,类型为T),并且每个value必须是唯一的,set 中的元素不能在容器中修改(元素总是const),但是可以从容器中插入或者删除他们; 在内部,set中的元素总是按照其内部比较对象(类型比较)所指示的特定严格弱排序准则...

C/C++菜鸟养成记 1063

Libero SoC v2021.1离线安装与IP核配置全攻略

本文详细介绍了Libero SoC v2021.1在离线环境下的完整安装与配置流程。核心内容包括如何选择正确的离线安装包、获取并配置许可证、安装与挂载MegaVault IP库,以及将ModelSim仿真器切换至免费SE模式的关键步骤。文章旨在帮助内网开发者避开常见陷阱,顺利完成FPGA开发环境的搭建。

weixin_29279101的博客 406

multiset的介绍及使用

multiset的介绍及使用 1、multiset的介绍 1、multiset是按照特定顺序存储元素的容器,其中元素是可以重复的 2、在multiset在,元素的value也会识别它组成的键值对,multiset元素的值不能在容器中进行修改,但可以插入和删除 3、在内部,multiset按照特定的严格弱排序准则进行排序 4、multiset容器通过key访问单个元素比unordered_multiset容器慢,但当使用迭代器遍历的时候,会得到一个有序序列 5、multiset的底层是二叉搜索树(红黑树)

gp1330782530的博客 1万+

Cadence Virtuoso IC617:从零构建传输门与反相器的Schematic设计实战

本文详细介绍了使用Cadence Virtuoso IC617进行传输门与反相器Schematic设计的完整流程,包括环境准备、原理图绘制、Symbol创建、仿真验证及实用技巧。通过分步指导和实战经验分享,帮助初学者快速掌握集成电路设计基础,提升EDA工具应用能力。

weixin_29194693的博客 596

利用PV操作控制进程的并发进行---经典题解

前趋图 先理清楚前趋图中的逻辑关系:P1没有前驱,P2的前驱是P1,P3的前驱是P1、P2,P4的前驱是P2,P5的前驱是P3、P4。 前驱就是指只有在前驱进程完成后,该进程才能开始执行。由图可知,这里进程之间有6条有向弧,分别表示为P1→P2,P1→P3,P2→P3,P2→P4,P3→P5,P4→P5, 各个进程间的逻辑关系,那么我们需要设定6个信号量(S1、S2、S3、S4、S5、S6),利用PV操作来控制这些过程。 对于第一个空,P1执行完成之后,需要通知P2、P3可以开始,此处需要V(S

Yan Ka Kue的博客 6136

set和mulitset区别

【代码】set和mulitset区别。

xms12_3的博客 429

生成式引擎优化(GEO):启动GEO优化的5个有效策略

随着生成式AI的普及,传统SEO正被GEO(生成式引擎优化)取代。本文提出GEO五大核心策略:用户意图解析、结构化内容设计、语义关键词优化、对话式内容创作和权威信源建设。研究表明,优化后的内容在AI答案中的引用率提升300%,点击率增长27%。文章还介绍了BERT模型、Schema标记等关键技术工具,并指出未来GEO将向多模态优化、实时数据更新方向发展。企业需避免简单堆砌关键词,应建立长期内容策略,通过结构化、权威性内容在AI时代保持竞争优势。

解锁AI流量新红利!🚀 GEO优化(生成引擎优化)助您掌控AI搜索,让AI成为您的品牌最佳代言人! 2785

multiset用法总结

       c++语言中,multiset是&lt;set&gt;库中一个非常有用的类型,它可以看成一个序列,插入一个数,删除一个数都能够在O(logn)的时间内完成,而且他能时刻保证序列中的数是有序的,而且序列中可以存在重复的数。 简单应用: 通过一个程序来看如何使用multiset: #include &lt;string&gt; #include &lt;iostream&gt; ...

二喵君的博客 13万+

Qt入门教程【高级控件篇】QModelIndex索引

QModelIndex索引

小鱼酱的博客 4465

激光雷达点云异常现象详解:鬼影、高反膨胀与拖点

现象核心外观主要成因核心硬件对策核心算法对策鬼影位置错误,出现"复制"的物体镜面反射/光学元件间杂散光物理光阑、抗反射涂层多帧时序一致性检验、反射率逻辑判断膨胀尺寸变大,轮廓呈毛刺状信号饱和、像素/通道串扰可变增益控制、随机编码序列强度阈值滤波、几何轮廓拟合(剪裁)拖点边缘粘连,出现"阶梯"或"连线"光斑跨立边缘、双回波融合小光斑光学设计、多回波支持邻域深度突变检测、波形脉宽分析这些异常现象是当前激光雷达感知中的核心难点,通常需要硬件物理特性优化与上层感知算法。

Fun_LiDAR的博客 299

[C++] STL (multi)map/(multi)set简介

容器类型在之前,我们已经接触过STL中的部分容器,比如vector,list,queue等。这些容器有一个共同的特点,他们都是序列式容器,因为其底层为线性序列的数据结构,并且里面存储的是数据本身,与关联式容器式不同的。关联式容器也是用来存储数据的,与序列式容器不同的是,其里面存储的是<key, value结构的键值对,在数据检索时比序列式容器效率更高。键值对用来表示对应关系的一种结构,这个结构中一般包含两个成员变量,key和value。key表示键值;value表示与key对应的信息。

石墨博客 1250

把 SAP S/4HANA 中的 Maintain Email Templates 用好:从模板维护、语言变体、业务绑定到传输治理的完整实践

摘要:SAP邮件模板管理常被低估,实则关乎审批通知、业务提醒等关键输出。官方推荐通过复制标准模板实现自定义,而非直接修改标准内容,以保持核心稳定。模板维护涉及语言变体、业务绑定、数据传输等治理环节,需业务顾问与开发团队协作确保字段来源与渲染逻辑。实施时需注意Fiori配置、权限分配及传输管理,避免测试与生产环境差异。模板设计应平衡灵活性与复杂度,遵循分层测试策略(内容、数据、流程),并建立命名规范以维护资产清晰度。(149字)

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 66

74.set,multiset和pair

Set的特性是。所有元素都会根据元素的键值自动被排序。Set的元素不像map那样可以同时拥有实值和键值,set的元素即是键值又是实值。Set不允许两个元素有相同的键值。 我们可以通过set的迭代器改变set元素的值吗?不行,因为set元素值就是其键值,关系到set元素的排序规则。如果任意改变set元素值,会严重破坏set组织。换句话说,set的iterator是一种const_iterator....

augfun的博客 286

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

泛型编程四:容器

STL有六大部件,容器、算法、仿函数、迭代器、适配器和分配器。除了算法是函数模板,其他都是类模板。容器可以分为序列容器和关联容器。常见的序列容器有vector、array、deque、list、forward-list,常见的关联容器有map、set、multimap和multiset。

weixin_45460969的博客 698

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

【STL】set和multiset的初步认知

set/multiset是一个集合容器,我们可以对这个容器进行插入,删除,查找等工作。set的元素内容只有一个键值(key,key和value为同一个值),不允许重复冗余,当对它插入一个已经存在的元素时,它会自动忽略。set/multiset的底层是用红黑树(RBTree)实现,拥有平衡二叉搜索树的结构,所以在进行检索时,效率会很高。而正因为它是一颗红黑树结构,当我们顺序遍历它时,序列是有序的。我们

LLZK_的博客 1870

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

C++——set/multiset再理解

1. 关联式容器 2. 键值对 3. 树形结构的关联式容器 4. set容器 4.1 set的介绍 4.2 set的使用 5. multiset 5.1multiset的介绍 5.2 mutiset的使用

m0_49687898的博客 713

c++Set和multiset容器/仿函数

类模板可以定义为仿函数,通过重载。

2302_79752447的博客 1297

【C++ STL】set/multiset 容器存储结构及常用成员方法操作

使用 set 当你需要一个容器存储唯一元素,且不允许重复。使用 multiset 当你需要一个容器存储元素,允许重复,并按照升序排序。在选择使用 set 还是 multiset 时,根据你的需求来决定是否允许重复元素。

qq_46403377的博客 1297

C++ set 的使用

set 的介绍 C++ 中set 类模板又称为集合类模板,它的主要特点就是元素会自动排序切不允许有重复的元素 不允许直接修改元素值,不提供直接存取元素的任何操作函数 对上面的内容写一个demo证实下 #include <iostream> #include <string> using namespace std; #include <set> int main() { // 创建一个空的set set<int> a; a.

小牧在一直在学习,在前进的道路上大家一起学习,进步。 1836

C++学习路线之C++基础(十二)——set容器,map容器和函数对象

所有元素在插入时自动排序。set/muliset容器属于关联式容器,底层结构是用实现。

enentohaha的博客 220

C++set容器,自定义排序方法(使用仿函数(Functor)或者普通函数指针)

在使用STL中的set容器时,如果需要自定义排序规则,可以使用仿函数(Functor)或者普通函数指针。使用普通函数指针时,需要定义一个比较函数,该函数接受两个参数,返回一个bool类型的值,表示两个参数的大小关系。在创建set容器时,将比较函数的函数指针作为第二个参数传递给set,从而实现按照自定义规则进行排序。int age;在上面的代码中,AgeLess是一个比较函数,它接受两个参数s1和s2,返回一个bool类型的值,表示s1和s2的大小关系。

Dontla的博客 9003

C++——set 和 multiset

  文章目录       Set 和 multiset 会根据特定的排序准则,自动将元素排序。两者不同之处在于 multiset 允许元素重复而 set 不允许。 set 和 multiset 包含在头文件中: #include <set> 在这个头文件中,上述两个类型都被定义为命名空间 std 内的 class template: namespace std { template <typename T, typename Compare =

qwjy的博客 5519

【C++】multiset用法

转自:https://blog.youkuaiyun.com/sodacoco/article/details/84798621        c++语言中,multiset是<set>库中一个非常有用的类型,它可以看成一个序列,插入一个数,删除一个数都能够在O(logn)的时间内完成,而且他能时刻保证序列中的数是有序的,而且序列中可以存在重复的数。 简单应用: 通过一个

ClimberCoding 6958

大爱C++——set容器使用仿函数

前面博客介绍过set容器了,这里还是简介一下set容器: 一:set容器简介 1.set是一个集合容器,其中所包含的元素是唯一的,集合中的元素按一定的顺序排列。元素插入过程是按排序规则插入,所以不能指定插入位置。 2.set采用红黑树变体的数据结构实现,红黑树属于平衡二叉树。在插入操作和删除操作上比vector快。 3.set不可以直接存取元素。(不可以使用at.(pos)与[]操作符

sum_TW的博客 3580

map和set(仿函数控制比较大小)

set(去重与排序) multiset(排序,无去重) map(里面使用pair存储数据) C++98 单参数构造函数才可以隐式类型转换,多参数不可以 任意类型都可以做key和value,如果没有比较大小,就写一个仿函数。 set("insert") √ map("insert","插入")× C++11支持多参数隐式类型转换 当你有多个值需要返回时,将这些值定义成一个结构返回 传参要注意传的是类型(Compare)还是对象(comp) 自己写仿函数,控制比较规则

2202_75625589的博客 308
上一篇: C++ set 和 multiset 容器
下一篇: C++ map 和 multimap 容器
cpp_learners
博客等级 码龄7年 1526粉丝 274原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

打赏作者

cpp_learners

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

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

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

打赏作者

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

抵扣说明:

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

余额充值