C++入门14——set与map的使用

news2025/1/26 14:30:18

在本专栏的往期文章中,我们已经学习了STL的部分容器,如vector、list、stack、queue等,这些容器统称为序列式容器,因为其底层是线性序列的数据结构,里面存储的是元素本身。而本篇文章我们要来认识一下关联式容器。

🥇关联式容器

在介绍关联式容器之前,先来回顾一下已经学习的数据结构9——二叉搜索树,在这篇文章中,我们认识了什么是K模型和KV模型:

K模型:只有Key作为关键码,结构中只需要存储Key,关键码即为需要搜索到的值。

KV模型:每一个关键码key,都有与之对应的值Value,即的键值对。

有了这个前提,我们就可以认为:

关联式容器就是KV模型的一种应用,关联式容器也是用来存储数据的,与序列式容器不同的是,其里面存储的是结构的键值对,在数据检索时比序列式容器效率更高。

根据应用场景的不同,STL一共实现了两种不同结构的管理式容器:树型结构与哈希结构。树型结 构的关联式容器主要有四种:map、set、multimap、multiset。这四种容器的共同点是:使用平衡搜索树(平衡搜索树是一种二叉搜索树)作为其底层结果,容器中的元素是一个有序的序列。

🥇set

🥈set的官网介绍

1. set是按照一定次序存储元素的容器;

2. 在set中,元素的value也标识它(value就是key,类型为T),并且每个value必须是唯一的。 set中的元素不能在容器中修改(元素总是const),但是可以从容器中插入或删除它们;

3. 在内部,set中的元素总是按照其内部比较对象(类型比较)所指示的特定严格弱排序准则进行排序;

4. set容器通过key访问单个元素的速度通常比unordered_set容器慢,但它们允许根据顺序对 子集进行直接迭代;

5. set在底层是用二叉搜索树(红黑树)实现的。

🥈set的使用

🥉插入

int main()
{
	set<int> s;
	//1.插入
	s.insert(8);
	s.insert(1);
	s.insert(7);
	s.insert(13);
	s.insert(6);
	s.insert(3);
	s.insert(5);
	s.insert(9);
	s.insert(14);
	s.insert(9);
	return 0;
}

🥉遍历

int main()
{
	set<int> s;
	//1.插入
	s.insert(8);
	s.insert(1);
	s.insert(7);
	s.insert(13);
	s.insert(6);
	s.insert(3);
	s.insert(5);
	s.insert(9);
	s.insert(14);
	s.insert(9);
	//2.迭代器遍历
	set<int>::iterator it = s.begin();
	while (it != s.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;
	//3.范围for遍历
	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;
	return 0;
}

🥉查找

//4.查找
	set<int>::iterator pos = s.find(14);
	if (pos != s.end())
	{
		cout << "已找到" << endl;
	}

🥉删除

//5.删除
	//①   用此方法删除,目标值存在就删除,不存在不做任何处理
	s.erase(2);
	s.erase(1);
	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;
	//②   用此方法删除,目标值存在就删除,不存在会程序报错
	pos = s.find(8);
	s.erase(pos);
	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;
	pos = s.find(1);
	s.erase(pos);

🥉lower_bound与upper_bound

//6.lower_bound与upper_bound	3 5 6 7 9 13 14
	auto start = s.lower_bound(3);  //lower_bound返回的值:>=val
	cout << *start << endl;

	auto finish = s.upper_bound(7); //upper_bound的返回值:>val
	cout << *finish << endl;
    //找区间[3,7]
	//while (start != finish)
	//{
	//	cout << *start << " ";
	//	++start;
	//}
	//cout << endl;
	//删除区间[3,7]
	s.erase(start, finish);
	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;

🥈set小结

①与map/multimap不同,map/multimap中存储的是真正的键值对<key,value>,set中只放 value,但在底层实际存放的是由<value,value>构成的键值对;

②set中插入元素时,只需要插入value即可,不需要构造键值对;

③set中的元素不可以重复(因此可以使用set进行去重);

④使用set的迭代器遍历set中的元素,可以得到有序序列;

⑤set中的元素默认按照小于来比较;

⑥set中查找某个元素,时间复杂度为:log_2 n;

⑦set中的元素不允许修改(因为修改之后不能保证二叉搜索树的有序性);

⑧set中的底层使用二叉搜索树(红黑树)来实现。

🥇multiset

🥈multiset的官网介绍

1. multiset是按照特定顺序存储元素的容器,其中元素是可以重复的;

2. 在multiset中,元素的value也会识别它(因为multiset中本身存储的就是<value,value>组成的键值对,因此value本身就是key,key就是value,类型为T),multiset元素的值不能在容器中进行修改(因为元素总是const的),但可以从容器中插入或删除; 

3. 在内部,multiset中的元素总是按照其内部比较规则(类型比较)所指示的特定严格弱排序准则进行排序;

4. multiset容器通过key访问单个元素的速度通常比unordered_multiset容器慢,但当使用迭代器遍历时会得到一个有序序列;

5. multiset底层结构为二叉搜索树(红黑树)。

🥈multiset的使用

multiset的使用与set的使用大致相同,下面演示区别较大的地方:

🥉插入

int main()
{
	multiset<int> s;
	//1.插入
	s.insert(8);
	s.insert(1);
	s.insert(7);
	s.insert(13);
	s.insert(6);
	s.insert(3);
	s.insert(5);
	s.insert(9);
	s.insert(14);
	s.insert(9);
	s.insert(9);
	s.insert(9);
	s.insert(9);

	multiset<int>::iterator it = s.begin();
	while (it != s.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;
	return 0;
}

也就是说,set用来去重+排序,multiset用来排序

🥉计数

//序列有几个9
cout << s.count(9) << endl;

🥉查找

 当序列中有多个重复的值时,multiset的find返回中序遍历的第一个数!

//3.查找
	it = s.find(9);
	while (it != s.end() && *it == 9)
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;

 

🥈multiset小结

①multiset中在底层中存储的是的键值对;

②mtltiset的插入接口中只需要插入即可;

③与set的区别是,multiset中的元素可以重复,set中value是唯一的;

④使用迭代器对multiset中的元素进行遍历,可以得到有序的序列;

⑤multiset中的元素不能修改;

⑥在multiset中找某个元素,时间复杂度为O(log_2 N);

⑦multiset的作用:可以对元素进行排序。

🥇map

🥈map的官网介绍

1. map是关联式容器,它是按照特定的次序(按照key来比较)存储,是由键值key和值value组合而成的元素;

2. 在map中,键值key通常用于排序和唯一地标识元素,而值value中存储与此键值key关联的内容。键值key和值value的类型可能不同,并且在map的内部,key与value通过成员类型 value_type绑定在一起,为其取别名称为pair: typedef pair value_type;

3. 在内部,map中的元素总是按照键值key进行比较排序的;

4. map中通过键值访问单个元素的速度通常比unordered_map容器慢,但map允许根据顺序对元素进行直接迭代(即对map中的元素进行迭代时,可以得到一个有序的序列);

5. map支持下标访问符,即在[ ]中放入key,就可以找到与key对应的value;

6. map通常被实现为二叉搜索树(更准确的说:平衡二叉搜索树(红黑树))。

🥈map的使用

🥉插入

//1.插入
	map<string, string> dict;
	dict.insert(pair<string, string>("pear", "梨"));

	//pair<string, string> kv("peach", "桃子");
	pair<string, string> kv = { "peach", "桃子" };
	dict.insert(kv);

	//C++11 多参数隐式类型转换(构造函数)
	dict.insert({ "apple", "苹果" });

	//C++98
	dict.insert(make_pair("banana", "香蕉"));
    dict.insert(make_pair("banana", "香蕉2"));

🥉遍历

//2.遍历
	//①迭代器遍历
	map<string, string>::iterator it = dict.begin();
	while (it != dict.end())
	{
		//cout << *it << endl;
		//cout << (*it).first << (*it).second << endl;
		cout << it->first << it->second << endl;
		++it;
	}
	cout << endl;
	//②范围for遍历
	for (auto& kv : dict)
	{
		cout << kv.first << ":" << kv.second << endl;
	}
	cout << endl;

结果如图:

由打印结果可知:

map的遍历顺序并不是按照插入顺序遍历的,而是按照ASCII码表的顺序遍历的;

map与set相似,插入的key相同,value不同,不会插入也不会更新。

🥉计数+[ ]的使用

 ①:

//①
	string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜",
"苹果", "香蕉", "苹果", "西瓜", "香蕉", "草莓" };
	map<string, int> countMap;
	for (auto& e : arr)
	{
		map<string, int>::iterator it = countMap.find(e);
		if (it != countMap.end())
		{
			it->second++;
		}
		else
		{
			countMap.insert(make_pair(e, 1));
		}
	}
	for (auto& kv : countMap)
	{
		cout << kv.first << ":" << kv.second << endl;
	}
	cout << endl;

结果如图:

②:

operator[]的原理是:  用<key,T()>构造一个键值对,然后调用insert()函数将该键值对插入到map中  ,如果key已经存在,插入失败,insert函数返回该key所在位置的迭代器  

如果key不存在,插入成功,insert函数返回新插入元素所在位置的迭代器,operator[]函数最后将insert返回值键值对中的value返回

详解会体现在代码里:

//②
	string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜",
"苹果", "香蕉", "苹果", "西瓜", "香蕉", "草莓" };
	map<string, int> countMap;
	for (auto& e : arr)
	{
		pair<map<string, int>::iterator, bool> ret;
		ret = countMap.insert(make_pair(e, 1));
		//insert的返回值类型为pair
		//而insert的返回值类型pair的第一个参数为iterator,第二个参数为bool

		//若“e”已经存在,则插入失败,insert返回该“e”所在位置的迭代器和false
		//若“e”不存在,则插入成功,insert返回新插入元素所在位置的迭代器和true

		//而insert的返回值-迭代器解引用得到的也是pair类型,此pair类型的第一个参数为key,第二个参数为value

		//也可以理解为:insert的返回值为(kv,bool),kv的返回值为(k,v)
		if (ret.second == false)//ret的first是kv,second是bool
		{
			ret.first->second++;//first是kv,second是v
		}
	}
	for (auto& kv : countMap)
	{
		cout << kv.first << ":" << kv.second << endl;
	}
	cout << endl;

 上一段代码简单介绍map的 [ ] 是如何实现的:

V& operator[](const K& key)
{
	pair<iterator, bool> ret = insert(make_pair(key, V()));
	return ret.first->second;
}

那么②的代码就可以简写为:

//②--->③
	string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜",
"苹果", "香蕉", "苹果", "西瓜", "香蕉", "草莓" };
	map<string, int> countMap;
	for (auto& e : arr)
	{
		countMap[e]++;
	}
	for (auto& kv : countMap)
	{
		cout << kv.first << ":" << kv.second << endl;
	}
	cout << endl;

 结果如图:

[]总结: 

 所以[]又兼具:

①插入;②查找;③修改;④插入+修改

int main()
{
	map<string, string> dict;
	dict.insert(make_pair("apple", "苹果"));
	dict.insert(make_pair("pear", "梨"));
	//插入
	dict["插入"];
	//查找
	cout << dict["pear"] << endl;
	//修改
	dict["apple"] = "大苹果";
	//插入+修改
	dict["pear2"] = "梨2";

	for (auto& kv : dict)
	{
		cout << kv.first << ":" << kv.second << endl;
	}
	return 0;
}

🥈map小结

①map中的的元素是键值对;

②map中的key是唯一的,并且不能修改;

③默认按照小于的方式对key进行比较;

④map中的元素如果用迭代器去遍历,可以得到一个有序的序列;

⑤map的底层为平衡搜索树(红黑树),查找效率比较高O(log_2 N);

⑥支持[]操作符,operator[]中实际进行插入查找。

🥇multimap

🥈multimap的官网介绍

1. Multimaps是关联式容器,它按照特定的顺序,存储由key和value映射成的键值对,其中多个键值对之间的key是可以重复的;

2. 在multimap中,通常按照key排序和惟一地标识元素,而映射的value存储与key关联的内容。key和value的类型可能不同,通过multimap内部的成员类型value_type组合在一起, value_type是组合key和value的键值对: typedef pair value_type;

3. 在内部,multimap中的元素总是通过其内部比较对象,按照指定的特定严格弱排序标准对 key进行排序的;

4. multimap通过key访问单个元素的速度通常比unordered_multimap容器慢,但是使用迭代 器直接遍历multimap中的元素可以得到关于key有序的序列;

5. multimap在底层用二叉搜索树(红黑树)来实现。

🥈multimap的使用

 multimap与map类似,不同点是,multimap支持冗余:

    multimap<string, string> dict;
	dict.insert(make_pair("banana", "香蕉"));
	dict.insert(make_pair("banana", "香蕉2"));
	dict.insert(make_pair("peach", "桃子"));
	dict.insert(make_pair("peach", "桃子2"));
	dict.insert(make_pair("pear", "梨"));
	dict.insert(make_pair("apple", "苹果"));
	for (auto& kv : dict)
	{
		cout << kv.first << ":" << kv.second << endl;
	}
	cout << endl;

结果如图:

🥈multimap小结

①multimap中的key是可以重复的;

② multimap中的元素默认将key按照小于来比较;

③multimap中没有重载operator[]操作(同学们可思考下为什么?);

④使用时与map包含的头文件相同。

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

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

相关文章

996引擎 - 前期准备-配置开发环境

996引擎 - 前期准备 官网搭建服务端、客户端单机搭建 开发环境配置后端开发环境配置环境 前端开发环境配置环境 后端简介前端简介GUILayoutGUIExport 官网 996传奇引擎官网 所有资料从官网首页开始&#xff0c;多探索。 文档&#xff1a; 996M2-服务端Lua 996M2-客户端Lua 搭…

Java程序员如何设计一个高并发系统?

前言 无论是职场新人还是有一定工作经验的老手&#xff0c;系统设计问题都如同悬在头顶的达摩克利斯之剑。对于新人而言&#xff0c;面试时遭遇“如何从零开始设计一个完整系统”的问题&#xff0c;往往让人瞬间大脑一片空白。系统设计的范畴广泛&#xff0c;网络资源难以全面…

RV1126画面质量三:QP调节

一&#xff0e;什么是 QP 调节&#xff1f; QP 参数调节&#xff0c;指的是量化参数调节。它主要是来调节图像的细节&#xff0c;最终达到调节画面质量的作用。QP 值和比特率成反比&#xff0c;QP值越小画面质量越高&#xff1b;反之 QP 值越大&#xff0c;画面质量越低…

渐变颜色怎么调?

渐变颜色的调整是设计中非常重要的一部分&#xff0c;尤其是在创建具有视觉吸引力和深度感的设计作品时。以下是一些在不同设计软件中调整渐变颜色的详细步骤和技巧&#xff1a; 一、Adobe Photoshop 1. 创建渐变 打开渐变工具&#xff1a; 选择工具栏中的“渐变工具”&#x…

Arduino基础入门学习——OLED显示屏的基本使用

Arduino基础入门学习——OLED显示屏的基本使用 一、前言二、准备工作三、基本使用1. OLED显示基本字符 &#xff08;数字英文基本标点符号&#xff09;2. OLED显示汉字3. 显示图片 四、 结束语 一、前言 在我们的日常开发中&#xff0c;一般有这么几种方式对数据进行展示&#…

jQuery阶段总结(二维表+思维导图)

引言 经过23天的学习&#xff0c;期间有期末考试&#xff0c;有放假等插曲。本来应该在学校里学习&#xff0c;但是特殊原因&#xff0c;让回家了。但是在家学习的过程&#xff0c;虽然在学&#xff0c;很让我感觉到不一样。但是效果始终还是差点的&#xff0c;本来17、18号左右…

无公网IP 外网访问媒体服务器 Emby

Emby 是一款多媒体服务器软件&#xff0c;用户可以在 Emby 创建自己的个人多媒体娱乐中心&#xff0c;并且可以跨多个设备访问自己的媒体库。它允许用户管理传输自己的媒体内容&#xff0c;比如电影、电视节目、音乐和照片等。 本文将详细的介绍如何利用 Docker 在本地部署 Emb…

PAT甲级-1022 Digital Libiary

题目 题目大意 一个图书有图书id&#xff0c;书名&#xff0c;作者&#xff0c;关键字&#xff0c;出版商&#xff0c;出版时间6个信息。现要查询图书的ID&#xff0c;1对应通过书名查询&#xff0c;2对应作者&#xff0c;3对应关键字&#xff08;不需要完全一致&#xff0c;包…

OpenCV:在图像中添加高斯噪声、胡椒噪声

目录 在图像中添加高斯噪声 高斯噪声的特性 添加高斯噪声的实现 给图像添加胡椒噪声 实现胡椒噪声的步骤 相关阅读 OpenCV&#xff1a;图像处理中的低通滤波-CSDN博客 OpenCV&#xff1a;高通滤波之索贝尔、沙尔和拉普拉斯-CSDN博客 OpenCV&#xff1a;图像滤波、卷积与…

二叉树的存储(下)c++

链式存储 我们可以创建两个数组L[N]、r[N]&#xff0c;分别存储i 号结点的左右孩子的编号&#xff0c;这样就可以通过数组下标实现链式访问。 本质上还是孩子表示法&#xff0c;存储的是左右孩子的信息 #include <iostream>using namespace std;const int N 1e6 10; …

回归预测 | MATLAB基于TCN-BiGRU时间卷积神经网络结合双向门控循环单元多输入单输出回归预测

效果一览 基本介绍 回归预测 | MATLAB基于TCN-BiGRU时间卷积神经网络结合双向门控循环单元多输入单输出回归预测 一、引言 1.1、研究背景及意义 在当今数据驱动的时代&#xff0c;时间序列预测已成为金融、气象、工业控制等多个领域的关键技术。随着人工智能和机器学习技术的…

如何获取小程序的code在uniapp开发中

如何获取小程序的code在uniapp开发中&#xff0c;也就是本地环境&#xff0c;微信开发者工具中获取code&#xff0c;这里的操作是页面一进入就获取code登录&#xff0c;没有登录页面的交互&#xff0c;所以写在了APP.vue中&#xff0c;也就是小程序一打开就获取用户的code APP.…

BGP边界网关协议(Border Gateway Protocol)路由聚合详解

一、路由聚合 1、意义 在大规模的网络中&#xff0c;BGP路由表十分庞大&#xff0c;给设备造成了很大的负担&#xff0c;同时使发生路由振荡的几率也大大增加&#xff0c;影响网络的稳定性。 路由聚合是将多条路由合并的机制&#xff0c;它通过只向对等体发送聚合后的路由而…

《用DOTS解决实际需求》集锦

去年作者发布了一篇《DOTS-ECS系列课程》&#xff0c;深受同学们的好评&#xff01;前期课程是基于0.51版本录制的&#xff0c;DOTS升级至1.0版本后&#xff0c;同学们纷纷希望能使用DOTS 1.0版本录制实战课程。 今年作者带着DOTS 1.0版本的实战课程回来啦&#xff01;&#x…

pycharm 运行远程环境问题 Error:Failed to prepare environment.

问题排查 拿到更详细的报错信息&#xff1a; Help > Diagnostic Tools > Debug Log Settings section: 添加下面的配置 com.intellij.execution.configurations.GeneralCommandLine 重显报错&#xff0c;我这里是再次运行代码打开 Help | Collect Logs and Diagnosti…

11、性能测试及监控Nginx动静分离配置

1、Jconsole使用 1、win cmd窗口输入jconsole打开工具 选择需要监控的应用程序&#xff0c;点击连接即可进行监控 2、jvisualvm监控工具 1、cmd控制台输入jvisualvm打开工具 运行&#xff1a;正在运行的 休眠&#xff1a;sleep 等待&#xff1a;wait 驻留&#xff1a;线…

流行的开源高性能数据同步工具 - Apache SeaTunnel 整体架构运行原理

概述 背景 数据集成在现代企业的数据治理和决策支持中扮演着至关重要的角色。随着数据源的多样化和数据量的迅速增长&#xff0c;企业需要具备强大的数据集成能力来高效地处理和分析数据。SeaTunnel通过其高度可扩展和灵活的架构&#xff0c;帮助企业快速实现多源数据的采集、…

【Address Overfitting】解决过拟合的三种方法

目录 1. 收集更多数据实践方法&#xff1a;适用场景&#xff1a;优缺点&#xff1a; 2. 特征选择方法介绍&#xff1a;实践示例&#xff1a;适用场景&#xff1a;优缺点&#xff1a; 3. 正则化&#xff08;Regularization&#xff09;正则化类型&#xff1a;实践示例&#xff1…

机器人SLAM建图与自主导航

前言 这篇文章我开始和大家一起探讨机器人SLAM建图与自主导航 &#xff0c;在前面的内容中&#xff0c;我们介绍了差速轮式机器人的概念及应用&#xff0c;谈到了使用Gazebo平台搭建仿真环境的教程&#xff0c;主要是利用gmapping slam算法&#xff0c;生成一张二维的仿真环境…

士的宁(strychnine)的生物合成-文献精读104

Biosynthesis of strychnine 士的宁&#xff08;strychnine&#xff09; 又名 番木鳖碱 的生物合成 摘要 士的宁&#xff08;番木鳖碱&#xff09;是一种天然产物&#xff0c;通过分离、结构阐明和合成努力&#xff0c;塑造了有机化学领域。目前&#xff0c;士的宁因其强大的…