【C++】set/map 与 multiset/multimap

news2024/11/25 7:15:01

✨✨欢迎大家来到Celia的博客✨✨

🎉🎉创作不易,请点赞关注,多多支持哦🎉🎉

所属专栏:C++

个人主页:Celia's blog~

目录

​编辑

序列式容器和关联式容器

一、set

1.1 set介绍

1.2 set功能

1.3 set成员函数

1.3.1 构造函数

1.3.2 迭代器

1.3.3 其他成员函数

二、map

2.1 map介绍

2.2 map功能

2.3 map成员函数

2.3.1 构造函数

2.3.2 迭代器

2.3.3 其他成员函数

2.3.3.1 insert

 2.3.3.2 []运算符重载

三、multiset

四、multimap


序列式容器和关联式容器

  • 在之前常用的STL容器中,有vector、list、queue、stack、string等。这些容器被称为序列式容器,它们底层的存储结构都是线性存储的,元素与元素之间没有明确的位置关系,交换序列式容器中的两个元素后,它们还是序列式容器。序列式容器中的元素是按照在容器中的储存位置和顺序进行保存和访问的。
  • 关联式容器与序列式容器不同的是,关联式容器中的元素都有明确的非线性逻辑结构,元素与元素间的位置关系也有着明确的标准,交换两个元素,逻辑结构就被破环了。关联式容器中的数据是按照键值来进行保存和访问的。常见的关联式容器有:set系列、map系列、unordered_set系列、unordered_map系列。
  • set和map是由红黑树实现的,红黑树是一个平衡二叉搜索树。set是<key>场景的结构,map是<key,value>场景的结构。

一、set

1.1 set介绍

  在C++中,map是一种关联性容器,用于存储唯一的值。底层用二叉搜索树(红黑树)来实现。用于对数据的有序存储和快速查找。

1.2 set功能

  set是一个类模板,T可以是任意类型,后两个参数一般不需要显式传递,如果想改变比较逻辑,可以传递第二个参数Compare。

  • set会按照一定顺序存储元素。使用迭代器能得到有序序列。
  • 元素的内容不能直接修改。
  • set中的元素都是唯一的,具有去重的特点。
  • set是一颗平衡二叉搜索树,查找效率为log_{2}N

1.3 set成员函数

1.3.1 构造函数

以下是常用的构造方式:

int main()
{
	//无参默认构造
	set<int> s1;
	//迭代器区间构造
	string str = "celia";
	set<int> s2(str.begin(), str.end());
	//拷贝构造
	set<int> s3 = s2;
	return 0;
}

1.3.2 迭代器

  • begin:获取容器中第一个元素的正向迭代器。
  • end:获取容器中最后一个元素下一个位置的正向迭代器。
  • rbegin:获取容器中最后一个元素的反向迭代器。
  • rend:获取容器中第一个元素前一个位置的反向迭代器。
int main()
{
	vector<int> v = { 9,6,4,7,2,1,3,5,0,8 };
	//迭代器区间构造
	set<int> s1(v.begin(), v.end());
	//正向迭代器遍历
	set<int>::iterator it = s1.begin();
	while (it != s1.end())
	{
		cout << *it << ' ';
		it++;
	}
	cout << endl;
	//反向迭代器遍历
	set<int>::reverse_iterator rit = s1.rbegin();
	while (rit != s1.rend())
	{
		cout << *rit << ' ';
		rit++;
	}
	cout << endl;
	return 0;
}

1.3.3 其他成员函数

insert插入一个元素
erase删除一个元素
find查找一个元素,返回一个迭代器
size返回容器元素个数
empty判断容器是否为空
swap交换两个容器中的数据
clear清空容器
count查找容器中指定元素的个数
int main()
{
	set<int> s1;
	//插入元素
	s1.insert(8);
	s1.insert(5);
	s1.insert(3);
	s1.insert(9);
	s1.insert(4);
	//插入返回一个pair<set<int>::iterator, bool> 
	auto pair = s1.insert(8);
	if (!pair.second) cout << "容器中已有该元素,插入失败" << endl;
	//删除元素
	for (auto x : s1) { cout << x << ' '; }cout << endl;
	s1.erase(s1.begin());//迭代器
	for (auto x : s1) { cout << x << ' '; }cout << endl;
	s1.erase(8);//指定元素
	for (auto x : s1) { cout << x << ' '; }cout << endl;
	s1.erase(s1.begin(), s1.end());//迭代器区间
	for (auto x : s1) { cout << x << ' '; }cout << endl;

	return 0;
}

insert插入元素时,会返回一个pair键值对(pair<set<T>::iterator, bool>),pair是一个类模板,其中有两个成员。insert返回的pair中,第二个成员表示插入是否成功,如果成功,第一个成员为新插入元素的迭代器,如果失败,第一个成员为与插入元素值相同等效元素迭代器。

int main()
{
	set<int> s1;
	s1.insert(8);
	s1.insert(5);
	s1.insert(3);
	s1.insert(7);
	s1.insert(6);
	//元素个数
	cout << s1.size() << endl;
	//查找元素,返回一个迭代器
	set<int>::iterator find = s1.find(3);
	cout << *find << endl;
	//判空
	cout << s1.empty() << endl;

	return 0;
}

int main()
{
	set<int> s1;
	s1.insert(8);
	s1.insert(5);
	s1.insert(3);
	s1.insert(7);
	s1.insert(6);

	set<int> s2;
	s2.insert(0);
	s2.insert(1);
	s2.insert(2);
	//交换
	s1.swap(s2);
	for (auto x : s1)
		cout << x << ' ';
	cout << endl;
	//清空
	s1.clear();
	cout << s1.empty() << endl;

	return 0;
}

二、map

2.1 map介绍

map与set的底层实现几乎一模一样,不同的地方在于,map中存储的是一个键值对pair

 pair中有两个成员,分别为T1类型的key,和T2类型的value。在map中,value的值可以改变,key的值不能直接改变。而二叉树中大小比较的规则是按照key的值进行比较的。

2.2 map功能

  • 按照特定次序(基于键值 key 比较)存储由键值 key 和值 value 组成的元素,使用迭代器遍历可得到有序序列。
  • 键值 key 用于排序和唯一标识元素,值 value 存储与键值关联的内容,键值和值的类型可不同。在内部,通过成员类型 value_type 将键值和值绑定并取别名为 pair 。
  • 元素的键值 key 不能修改,而值 value 可以修改,因为底层的二叉搜索树基于键值构建,而非值。
  • 内部按照键值进行比较排序,默认键值按小于比较,若未传入内部比较对象。
  • 支持下标访问符,在 [] 中放入键值 key ,可获取对应的 value 。
  • map是一颗平衡二叉搜索树,查找效率为log_{2}N

2.3 map成员函数

2.3.1 构造函数

map提供了以上方式的构造函数。

int main()
{
	int arr[] = { 0,1,2,3,4,5 };
	//默认无参构造
	map<int, int> m1;
	//迭代器构造
	map<int, int> m2(m1.begin(), m1.end());
	//拷贝构造
	map<int, int> m3(m2);
	return 0;
}

2.3.2 迭代器

  • begin:获取容器中第一个元素的正向迭代器。
  • end:获取容器中最后一个元素下一个位置的正向迭代器。
  • rbegin:获取容器中最后一个元素的反向迭代器。
  • rend:获取容器中第一个元素前一个位置的反向迭代器。
int main()
{
	map<int, string> m1;
	//插入
	m1.insert(pair<int, string>(1, "one"));
	m1.insert(pair<int, string>(2, "two"));
	m1.insert(pair<int, string>(3, "three"));
	//另一种方式
	m1.insert({4, "four"});
	m1.insert({5, "five"});
	//正向迭代器
	map<int, string>::iterator it = m1.begin();
	while (it != m1.end())
	{
		cout << it->first << " " << it->second << endl;
		it++;
	}
	cout << "==============================" << endl;
	//反向迭代器
	map<int, string>::reverse_iterator rit = m1.rbegin();
	while (rit != m1.rend())
	{
		cout << rit->first << " " << rit->second << endl;
		rit++;
	}
	return 0;
}

2.3.3 其他成员函数

insert插入元素
erase删除指定key值元素
find查找元素
size返回容器中元素数量
empty判空
clear清空容器
count返回容器中指定元素值的元素个数
swap交换两个容器中的数据
[]运算符重载根据对应的key获取其val的值

有一部分成员函数的用法相同,这里着重介绍两个成员函数:insert和[]运算符重载。

2.3.3.1 insert
int main()
{
	map<int, string> m1;
	//插入
	m1.insert(pair<int, string>(1, "one"));
	m1.insert(pair<int, string>(2, "two"));
	m1.insert(pair<int, string>(3, "three"));
	m1.insert({ 4, "four" });
	m1.insert({ 5, "five" });
	map<int, string>::iterator it = m1.begin();
	while (it != m1.end())
	{
		cout << it->first << " " << it->second << endl;
		it++;
	}
	cout << "=============================" << endl;
	//删除
	m1.erase(3);
	it = m1.begin();
	while (it != m1.end())
	{
		cout << it->first << " " << it->second << endl;
		it++;
	}
	cout << "=============================" << endl;
	m1.erase(4);
	it = m1.begin();
	while (it != m1.end())
	{
		cout << it->first << " " << it->second << endl;
		it++;
	}
	return 0;
}

  • 由于map中存放的是键值对pair<T1, T2>,所以插入的时候需要构造一个pair来插入:
    //构造匿名对象
    m1.insert(pair<int, string>(1, "one"));
    
    //也可以这样写
    m1.insert({ 4, "four" });  //等同pair<int, string>(4, "four")
    
    //也可以通过make_pair函数的返回值进行构造
    m1.insert(make_pair(1, "one"));
  •  利用迭代器访问时,不能直接解引用it,而是需要通过it->来访问key和value。
  • insert函数的返回值也是一个pair<iterator, bool>
    若插入元素的key在map中不存在,则返回新插入元素的迭代器和true。
    若插入元素的key在map中已经存在,则返回map中与key值相等元素的迭代器和false。
 2.3.3.2 []运算符重载

map的[]运算符重载比较特殊,兼具插入、查找、修改为一体。

函数原型:

mapped_type& operator[] (const key_type& k);

mpped_typevalue的类型, key_typekey的类型。

函数底层实现方式:

(*((this->insert(make_pair(k, mapped_type()))).first)).second

这个地方可以分为三步:

  • 在函数内用this指针调用insert函数,插入一个键值对。
  • 接收insert函数的返回值(pair<iterator, bool>),并且取得这个pair的first(iterator)。
  • 对iterator解引用,取到其中的value值。

如果插入的元素在map中不存在,[]就相当于插入新元素,如果插入的元素在map中存在,[]就相当于拿到map中与待插入key值相同的元素的value。

有了这样的实现方式,我们就可以简化map函数的插入操作:

int main()
{
	map<int, string> m;
	m[0] = "zero";
	m[1] = "one";
	m[2] = "two";

	map<int, string>::iterator it = m.begin();
	while (it != m.end())
	{
		cout << it->first << " " << it->second << endl;
		it++;
	}
	return 0;
}

三、multiset

multiset与set的使用方法基本一致,唯一的区别是multiset允许存储重复元素

int main()
{
	multiset<int> s;
	s.insert(0);
	s.insert(0);
	s.insert(1);
	s.insert(1);
	s.insert(2);
	s.insert(2);
	for (auto x : s) { cout << x << ' '; }cout << endl;

	return 0;
}

在这里需要注意, multiset的find函数返回的是二叉树中序遍历第一个值为key元素的迭代器。

四、multimap

multimap与map是使用方式基本一致,唯一的区别是multimap允许存储重复元素

int main()
{
	multimap<int, string> m;
	m.insert({ 0, "zero"});
	m.insert({ 0, "zero"});
	m.insert({ 1, "one" });
	m.insert({ 1, "one" });
	m.insert({ 2, "two" });
	m.insert({ 2, "two" });
	map<int, string>::iterator it = m.begin();
	while (it != m.end())
	{
		cout << it->first << " " << it->second << endl;
		it++;
	}

	return 0;
}

这里需要注意 ,multimap的find函数返回的是二叉树中序遍历第一个值为key元素的迭代器。并且multimap并没有重载[]运算符,因为允许重复元素的存在,不能确定返回哪一个节点的value。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2208841.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

大健康零售电商的智囊团:知识中台的应用与影响

在数字化浪潮席卷各行各业的今天&#xff0c;大健康零售电商行业也在积极探索转型升级的新路径。知识中台&#xff0c;作为一种集知识管理、数据挖掘与智能化应用于一体的新型技术架构&#xff0c;正逐渐成为推动这一转型的关键力量。本文将深入探讨知识中台在大健康零售电商中…

Light灯光组件+组件的相关操作+游戏资源的加载

Light灯光组件 Type: Directional:平行光&#xff0c;模仿的是太阳光 Spot:聚光灯 Area:区域光 Color&#xff1a; 颜色值 Mode: RealTime:实时 Mix:混合 Baked:烘焙 Intersity: 光照强度 Indirect Multiplier:光照强度乘数 Shadow Type:影子设置&#xff1a;…

CV方法再学习

轻量化模型 Mobile系列(V1~V3) MobileNetV1 MobileNetV1之所以轻量&#xff0c;与深度可分离卷积的关系密不可分 深度可分离卷积 主要是两种卷积变体组合使用&#xff0c;分别为逐通道卷积&#xff08;Depthwise Convolution&#xff09;和逐点卷积&#xff08;Pointwise C…

Nginx UI 一个可以管理Nginx的图形化界面工具

Nginx UI 是一个基于 Web 的图形界面管理工具&#xff0c;支持对 Nginx 的各项配置和状态进行直观的操作和监控。 Nginx UI 的功能非常丰富&#xff1a; 在线查看服务器 CPU、内存、系统负载、磁盘使用率等指标 在线 ChatGPT 助理 一键申请和自动续签 Let’s encrypt 证书 在…

八、Python基础语法(判断语句-下)

一、if elif else 结构 应用场景&#xff1a;多个判断条件下&#xff0c;并且这些判断条件存在一定的关联。 语法&#xff1a; elif也是python中关键字&#xff0c;后面跟一个判断条件&#xff0c;判断条件后面跟冒号 存在冒号&#xff0c;需要换行缩进&#xff0c;处于elif…

金九银十软件测试面试题(800道)

今年你的目标是拿下大厂offer&#xff1f;还是多少万年薪&#xff1f;其实这些都离不开日积月累的过程。 为此我特意整理出一份&#xff08;超详细笔记/面试题&#xff09;它几乎涵盖了所有的测试开发技术栈&#xff0c;非常珍贵&#xff0c;人手一份 肝完进大厂 妥妥的&#…

QD1-P5 HTML 段落标签(p)换行标签(br)

本节视频 www.bilibili.com/video/BV1n64y1U7oj?p5 ‍ 本节学习 HTML 标签&#xff1a; p标签 段落br标签 换行 ‍ 一、p 标签-段落 1.1 使用 p 标签划分段落 <p>段落文本</p>示例 <!DOCTYPE html> <html><head><meta charset"…

算法剖析:滑动窗口

文章目录 前言一、长度最小的子数组二、无重复字符的最长子串三、最大连续1的个数 III四、将 x 减到 0 的最小操作数五、水果成篮六、找到字符串中所有字母异位词七、串联所有单词的子串八、最小覆盖子串总结 前言 滑动窗口可以看作为一种特殊的通向双指针&#xff0c;这两个指…

轻松翻译:顶尖翻译器评测!

在工作生活中如果遇到翻译需求&#xff0c;就少不了一些好用的翻译器&#xff0c;接下来是我们就来为大家推荐几款市面上口碑极佳的翻译软件&#xff01; 福昕在线翻译 直达链接&#xff1a; fanyi.pdf365.cn/ 操作教程&#xff1a;立即获取 福昕在线翻译是一款基于云端技…

关于部分股市买卖的演示和总结

本文是对上一文的补充&#xff1a;一个普通人的投资认知-CSDN博客 一、简介 假设公司A 向某交易所发行100股股票&#xff0c;每股5元&#xff0c;预计将融资500元。 股民a买了10股&#xff0c;付出50元。 股民b买了20股&#xff0c;付出100元。 股民c买了30股&#xff0c;付出…

【3维视觉】超级好用的3D模型交互式可视化工具viser

项目地址 https://github.com/nerfstudio-project/viser 功能 SMPL模型可视化编辑 点云可视化 3DGS实时渲染播放 安装和使用 安装viser git clone https://github.com/nerfstudio-project/viser.git使用 官方说明文档 1. SMPL模型可视化编辑 先下载SMPLX人体模型 下载解…

290. 单词规律【哈希表】

文章目录 290. 单词规律解题思路Go代码 290. 单词规律 290. 单词规律 给定一种规律 pattern 和一个字符串 s &#xff0c;判断 s 是否遵循相同的规律。 这里的 遵循 指完全匹配&#xff0c;例如&#xff0c; pattern 里的每个字母和字符串 s 中的每个非空单词之间存在着双向…

小程序知识付费的优势 知识付费服务 知识付费平台 知识付费方法

在信息爆炸的时代&#xff0c;知识如同繁星点点&#xff0c;璀璨而散落。如何在这片知识的海洋中精准捕捞&#xff0c;成为现代人追求自我提升的迫切需求。小程序知识付费&#xff0c;正是这样一座桥梁&#xff0c;它以独特的优势&#xff0c;让智慧触手可及&#xff0c;轻触未…

metahuman如何导入UE5

1.启动 通过EPIC启动UE5(UE5内置有Bridge, 但是UE4是需要单独下在Bridge软件) 2.打开Quixel Bridge 在window(窗口)中打开Quixel Bridge 3.Bridge界面 在弹出的Bridge界面选择模型 需要先下载&#xff0c;然后再导入 4.下载模型 点击需要的模型右上方的绿色箭头下载 5.下…

TensorRT-LLM七日谈 Day1

Flag 利用7天时间熟悉tensort-llm的代码架构&#xff0c;cublas的使用方式以及flash attention的调优。 项目链接 https://github.com/NVIDIA/TensorRT-LLM 安装 https://nvidia.github.io/TensorRT-LLM/installation/linux.html 它的安装主要是需要下载相应的docker镜像&am…

金奖!实在Agent智能体问鼎华为昇腾AI创新大赛

为推动浙江计算产业高质量发展&#xff0c;激发行业数智化原生创新与规模化应用&#xff0c;华为于10月10日在杭州举办“激发原生创新&#xff0c;共赢数智浙里”浙江鲲鹏昇腾产业与人才创新论坛暨鲲鹏&昇腾创新大赛2024浙江总决赛颁奖仪式。 中国工程院院士、浙江大学教授…

STM32学习--5-1 对射式红外传感器计次

接线图 原理图&#xff1a; CountSensor.c #include "stm32f10x.h" // Device headeruint16_t CountSensor_Count;void CountSensor_Init(void) {RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); // 开启APB2Periph外设GPIOB时钟RCC_APB2Pe…

react中css样式隔离

使用CSS Modules css模块化 1, 创建组件样式文件时以 xxx.module.css命名, 例如 Home.module.css 代替 Home.css 2, 在组件jsx导入样式文件时使用 import styles from ./xxx.module.css 导入 代替 import ./xxx.css 3, 在组件中需要设置样式的标签上添加class值, classNa…

xss-labs靶场第七关测试报告

目录 一、测试环境 1、系统环境 2、使用工具/软件 二、测试目的 三、操作过程 1、注入点寻找 2、使用hackbar进行payload测试 3、绕过结果 四、源代码分析 五、结论 一、测试环境 1、系统环境 渗透机&#xff1a;本机(127.0.0.1) 靶 机&#xff1a;本机(127.0.0.…

Apache SeaTunnel 9月份社区发展记录

各位热爱 SeaTunnel 的小伙伴们&#xff0c;9月份社区月报来啦&#xff01;这里将定期更新SeaTunnel社区每个月的重大进展&#xff0c;欢迎关注&#xff01; 月度Merge Stars 感谢以下小伙伴上个月为 Apache SeaTunnel 做的精彩贡献&#xff08;排名不分先后&#xff09;&…