【C++】学习笔记——map和set

文章目录

  • 十五、map和set
    • 1. 关联式容器
    • 2. set的介绍
    • 3. set的使用
    • 4. multiset
    • 5. map的介绍
    • 6. map的使用
    • 7. multimap
    • 8. map中重载的operator[]
  • 未完待续


十五、map和set

1. 关联式容器

我们已经接触过STL中的部分容器,比如:vectorlistdeque 等,这些容器统称为 序列式容器序列式容器底层的数据结构里面存储的是元素本身。
关联式容器也是用来存储数据的,与序列式容器不同的是,其 里面存储的是<key, value>结构的键值对 ,即底层的数据结构包含两个值,key代表键值value代表与key对应的信息

在数据检索时关联式容器比序列式容器效率更高。

而set和map就是STL中的 树形结构的关联式容器 。底层是平衡二叉树(红黑树)。

2. set的介绍

set文档

3. set的使用

使用set记得包含 set 头文件哦。
在这里插入图片描述
在这里插入图片描述

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

void test01()
{
	set<int> s;
	s.insert(5);
	s.insert(2);
	s.insert(4);
	s.insert(1);
	s.insert(3);
	s.insert(2);
	s.insert(1);

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

	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;
}

int main()
{
	test01();
	return 0;
}

对于 insert 的使用我们已经轻车熟路了。
在这里插入图片描述
我们发现结果跟插入的数据好像不匹配,这是因为set底层是平衡二叉树,自带排序属性,而且遇到重复的值不会再次插入,所以 set具有 排序 + 去重 的功能。
在这里插入图片描述

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

void test03()
{
	set<int> s;
	s.insert(5);
	s.insert(2);
	s.insert(4);
	s.insert(1);
	s.insert(3);
	s.insert(2);
	s.insert(1);

	set<int>::iterator it = s.find(5);
	// 使用迭代器进行删除时必须保证迭代器有效
	s.erase(it);
	// 使用指定value进行删除,如果该值存在则删除,不存在不做任何处理
	s.erase(666);

	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;
}

int main()
{
	test03();
	return 0;
}

在这里插入图片描述

当使用迭代器进行删除时确保迭代器有效,否则会报错。

在这里插入图片描述

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

void test02()
{
	set<int> s;
	s.insert(5);
	s.insert(2);
	s.insert(4);
	s.insert(1);
	s.insert(3);
	s.insert(2);
	s.insert(1);

	set<int>::iterator it = s.find(5);
	if (it != s.end())
	{
		cout << "找到了" << endl;
	}
}

int main()
{
	test02();
	return 0;
}

find查找到元素会返回一个指向元素的迭代器,没找到则返回指向end()的迭代器。
在这里插入图片描述

在这里插入图片描述
count()会返回这个值有几个。

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

void test04()
{
	set<int> s;
	s.insert(5);
	s.insert(2);
	s.insert(4);
	s.insert(1);
	s.insert(3);
	s.insert(2);
	s.insert(1);

	cout << s.count(1) << endl;
	cout << s.count(77) << endl;
}

int main()
{
	test04();
	return 0;
}

在这里插入图片描述

在这里插入图片描述

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

void test05()
{
	set<int> s;
	s.insert(5);
	s.insert(2);
	s.insert(4);
	s.insert(1);
	s.insert(6);
	s.insert(2);
	s.insert(1);

	// lower_bound返回 容器里第一个 >= value的值
	auto start = s.lower_bound(3);
	// opper_bound返回 容器里第一个 > value的值
	auto finish = s.upper_bound(5);
	cout << *start << endl;
	cout << *finish << endl;
	// 迭代器区间删除
	s.erase(start, finish);

	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;
}

int main()
{
	test05();
	return 0;
}

lower_bound返回 容器里第一个 >= value的值
opper_bound返回 容器里第一个 > value的值
在这里插入图片描述

4. multiset

multiset的用法与set基本一样,只是 multiset允许出现重复值
在这里插入图片描述
此时这里的返回值就有了意义,返回删除的元素个数。

在这里插入图片描述
当有重复值时,find返回的迭代器指向中序遍历的第一个要查找的值。

5. map的介绍

map文档
在这里插入图片描述
map底层其实是 pair 。而 pair 其实是一个类模板。
在这里插入图片描述

成员变量有两个,一个first,一个second,在map里,first一般存的是key,second存的是value
在这里插入图片描述

6. map的使用

使用map时记得包含 map 头文件哦。
在这里插入图片描述

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

void test01()
{
	map<string, string> dict;
	dict.insert(pair<string, string>("sort", "排序"));
	dict.insert(pair<string, string>("string", "字符串"));
	dict.insert({ "apple", "苹果" });
	dict.insert(make_pair("sort", "排序"));

	map<string, string>::iterator it = dict.begin();
	while (it != dict.end())
	{
		// 两种获取key和value的方法
		cout << (*it).first << " " << it->second << endl;
		++it;
	}
}

int main()
{
	test01();
	return 0;
}

make_pair是一个模板函数,跟pair那种写法没区别。
在这里插入图片描述
在这里插入图片描述
map同样具有 排序 + 去重 的功能,排序的依据是map的 key

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

void test02()
{
	map<string, string> dict;
	dict.insert(make_pair("sort", "排序"));
	dict.insert(make_pair("string", "字符串"));
	dict.insert(make_pair("sort", "xxxx"));

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

int main()
{
	test02();
	return 0;
}

此时第三个插入并不会插入,也不会更新。
在这里插入图片描述
map的其他成员函数基本没啥大的变化,我们不再赘述。

7. multimap

multimap跟map的区别与multiset与set的区别类似。
在这里插入图片描述

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

void test03()
{
	multimap<string, string> dict;
	dict.insert(make_pair("sort", "排序"));
	dict.insert(make_pair("string", "字符串"));
	dict.insert(make_pair("sort", "xxxx"));
	dict.insert(make_pair("sort", "排序"));

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

int main()
{
	test03();
	return 0;
}

在这里插入图片描述
此时就可以插入重复值了。(排序时只看key)

8. map中重载的operator[]

map的普通统计次数:

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

void test04()
{
	string arr[] = { "苹果","西瓜","苹果","西瓜","苹果","苹果","西瓜","苹果","香蕉","苹果","西瓜","香蕉","草莓" };
	map<string, int> countMap;

	for (auto& e : arr)
	{
		// 查找
		map<string, int>::iterator it = countMap.find(e);
		// 有则数量+1
		if (it != countMap.end())
		{
			it->second++;
		}
		// 没有则插入
		else
		{
			countMap.insert(make_pair(e, 1));
		}
	}

	for (auto& e : countMap)
	{
		cout << e.first << " " << e.second << endl;
	}
}

int main()
{
	test04();
	return 0;
}

在这里插入图片描述
在这里插入图片描述
当key存在时,operator[]可以返回这个key所映射的value的引用。
operator[]的访问原型:
在这里插入图片描述
在这里插入图片描述
map的insert函数返回一个pair,第二个数据代表是否插入成功,如果成功(第一次出现)则返回 true 。第一个数据代表指向这个key的迭代器(已经存在的或新插入的)。
所以上面的统计次数代码可以改成:

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

void test05()
{
	string arr[] = { "苹果","西瓜","苹果","西瓜","苹果","苹果","西瓜","苹果","香蕉","苹果","西瓜","香蕉","草莓" };
	map<string, int> countMap;

	for (auto& e : arr)
	{
		pair<map<string, int>::iterator, bool> ret;
		ret = countMap.insert(make_pair(e, 1));

		// 已经存在
		if (ret.second == false)
		{
			// 迭代器指向的value + 1
			ret.first->second++;
		}
	}

	for (auto& e : countMap)
	{
		cout << e.first << " " << e.second << endl;
	}
}

int main()
{
	test05();
	return 0;
}

在这里插入图片描述

所以operator[]的访问就跟insert差不多,插入的value是类型的默认构造值。所以上面的统计代码也可以写成:

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

void test06()
{
	string arr[] = { "苹果","西瓜","苹果","西瓜","苹果","苹果","西瓜","苹果","香蕉","苹果","西瓜","香蕉","草莓" };
	map<string, int> countMap;

	for (auto& e : arr)
	{
		countMap[e]++;
	}

	for (auto& e : countMap)
	{
		cout << e.first << " " << e.second << endl;
	}
}

int main()
{
	test06();
	return 0;
}

在这里插入图片描述

于是,插入也可以写成这样:

void test07()
{
	map<string, string> dict;

	// 插入
	dict["sort"];
	// 查找
	cout << dict["sort"] << endl;
	// 修改
	dict["sort"] = "xxx";
	// 插入 + 修改
	dict["apple"] = "苹果";
}

未完待续

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

04. Redis 配置文件

文章目录 单位包含网络 NETWORK通用 GENERAL快照 SNAPSHOTTING主从复制 REPLICATION安全 SECURITY客户端 CLIENTS内存设置 MEMORY MANAGEMENTAPPEND ONLY MODE 模式&#xff08;aof 的配置&#xff09; 单位 配置文件对大小写不敏感&#xff08;unit单位&#xff09;。 包含 …

通过域名接口申请免费的ssl多域名证书

来此加密已顺利接入阿里云的域名接口&#xff0c;用户只需一键调用&#xff0c;便可轻松完成域名验证&#xff0c;从而更高效地申请证书。接下来&#xff0c;让我们详细解读一下整个操作过程。 来此加密官网 免费申请SSL证书 免费SSL多域名证书&#xff0c;泛域名证书。 首先&a…

K8S认证|CKA题库+答案| 2. 查看Pod CPU资源使用量

2、查看集群中运行Pod CPU资源使用量 您必须在以下Cluster/Node上完成此考题&#xff1a; Cluster Master node Worker node k8s …

『Apisix安全篇』快速掌握APISIX Basic-Auth插件高效使用

&#x1f4e3;读完这篇文章里你能收获到 &#x1f468;‍&#x1f4bb; 学习如何快速安装并配置APISIX Basic-Auth插件&#xff0c;为您的API安全保驾护航。&#x1f6e0;️ 文章详细介绍了如何创建带有basic-auth配置的Consumer&#xff0c;以及如何在Route中启用该插件。&am…

爱校对:智能校对,让文字更专业

交互未来&#xff08;北京&#xff09;科技有限公司&#xff0c;源自清华大学计算机智能人机交互实验室&#xff0c;致力于通过高科技手段提升用户体验&#xff0c;实现“科技让生活更美好”的宗旨。我们的产品——爱校对&#xff0c;正是这种创新精神的结晶&#xff0c;旨在为…

怎样策划一场价值百万的营销活动?

策划一场活动听起来是不是就有点头大&#xff1f; 别急&#xff0c;其实只要掌握了活动策划的精髓&#xff0c;一步步来&#xff0c;从构思到实施&#xff0c;整个过程都能游刃有余。 一、定下目标&#xff1a; 咱们先得搞清楚&#xff0c;这场活动到底是为了啥。是想提升品…

代码随想录-Day17

110. 平衡二叉树 这道题中的平衡二叉树的定义是&#xff1a;二叉树的每个节点的左右子树的高度差的绝对值不超过 111&#xff0c;则二叉树是平衡二叉树。根据定义&#xff0c;一棵二叉树是平衡二叉树&#xff0c;当且仅当其所有子树也都是平衡二叉树&#xff0c;因此可以使用递…

四天学会JS高阶(学好vue的关键)——构造函数数据常用函数(理论+实战)(第二天)

一、对象创建引发构造函数产生 1.1 创建对象三种方式&#xff1a; 利用对象字面量创建对象 const obj {name: 佩奇}注&#xff1a;对象字面量的由来&#xff1a;即它是直接由字面形式&#xff08;由源代码直接&#xff09;创建出来的对象&#xff0c;而不是通过构造函数或者…

开箱测评!吸猫毛除味神器,希喂FreAir Lite宠物空气净化器实测

掉毛季又来了&#xff0c;猫咪的毛发满天飞&#xff0c;怎么办&#xff1f;我家掉毛怪一到季节就开始掉老多毛&#xff0c;关键还喜欢在家里打架跑酷&#xff01;天上地下都是毛&#xff01;为了减少家里空气中浮毛&#xff0c;你做过那些努力呢&#xff1f;最近猫掉毛掉的&…

设置height:100%不生效的原因

之前网课案例总是不屑于去看&#xff0c;因为总觉得太花时间&#xff0c;但是不可否认的是&#xff0c;认真去看还是会有收获的&#xff0c;而且常有意外收获 昨天在看实现动画效果的综合案例中&#xff0c;意外解决了我长久以来的一个疑问&#xff1a;为什么给元素设置height…

论文精读--InstructGPT

模型效果取决于数据效果&#xff0c;但在精细度上控制不够&#xff0c;只是大力出奇迹&#xff0c;这样有很大的问题&#xff1a; &#xff08;1&#xff09;数据量太多或者没有这方面的数据&#xff0c;模型学不会怎么办 &#xff08;2&#xff09;安全性问题&#xff0c;模…

踩坑——纪实

开发踩坑纪实 1 npm安装1.1 查看当前的npm镜像设置1.2 清空缓存1.3 修改镜像1.4 查看修改结果1.5 重新安装vue 2 VScode——NPM脚本窗口找不到3 springboot项目中updateById()失效4 前端跨域4.1 后端加个配置类4.2 CrossOrigin注解 5 路由出口6 springdoc openapi3 swagger3文件…

VMware 虚拟机 VM10~17系列安装教程(功能最强大的电脑虚拟机软件)

前言 VMware是功能最强大的虚拟机软件&#xff0c;用户可以在虚拟机同时运行各种操作系统&#xff0c;进行开发、测试、演示和部署软件&#xff0c;虚拟机中复制服务器、台式机和平板环境&#xff0c;每个虚拟机可分配多个处理器核心、主内存和显存。 系统要求 VM17 VM16&am…

《ESP8266通信指南》番外-(附完整代码)ESP8266获取DHT11接入(基于Lua)

前言 此篇为番外篇,是 ESP8266 入门的其他功能教程,包括但不限于 DHT11 驱动TCP 通信Thingsboard 平台的接入阿里云物联网云平台接入华为云平台接入 1. 小节目标 使用 Lua 驱动 DHT11 传感器,获取温湿度的值 2. 进入主题 NodeMCU 基于 LUA 相关资料 官方文档&#xff1a;…

【每日刷题】Day47

【每日刷题】Day47 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; &#x1f33c;文章目录&#x1f33c; 1. 112. 路径总和 - 力扣&#xff08;LeetCode&#xff09; 2. 2404. 出现最频繁的偶数元素 - 力扣&am…

Visual Basic6.0零基础教学(5)—VB的输入输出,顺序和选择结构

VB的输入输出和控制结构 文章目录 VB的输入输出和控制结构前言一、输入输出1. InputBox 输入2.MsgBox输出print 输出 二、控制结构1.顺序结构赋值语句 2.选择结构if ... then单分支if ... then...else.... 双分支if ... then... elseif ... then .. else ... 多分支Select Case…

视频监控管理平台LntonCVS监控视频汇聚融合云平台主要功能应用场景介绍

随着网络技术的不断发展和万物互联时代的到来&#xff0c;视频融合在一些系统集成项目及综合管理应用中变得日益重要。本文以LntonCVS视频融合云平台为案例&#xff0c;探讨视频融合的对象及其应用场景。 1. 视频监控设备 视频监控摄像设备是各种视频应用项目的基础部分。在视…

CSS单行、同行文本左右对齐

再项目需求中&#xff0c;UI小姐姐常常要考虑项目的排版样式更简洁高级&#xff0c;常常会在项目设置内容或者字体两端对齐的效果&#xff0c;比如&#xff0c;在做表单时我们经常遇到让上下两个字段对齐的情况&#xff0c;比如姓名&#xff0c; 手机号码&#xff0c; 出生地等…

VUE3+Vite+vant4从零开始构建前端项目

VUE3Vitevant4从零开始构建前端项目 1. 环境准备Node.js 安装 2. Vite 构建项目3. 集成Vant41. 安装Vant 组件2. 引入组件3. 使用vant按钮组件 1. 环境准备 Node.js 安装 Node.js官网地址&#xff1a;https://nodejs.p2hp.com/ 下载最新的版本&#xff0c;下载文件为msi结尾的…

[力扣]——70.爬楼梯

题目描述&#xff1a; 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢&#xff1f; 本题较为简单&#xff0c;主要用到递归思想 int fun(int n,int memo[]) {if(memo[n]!-1) //如果备忘录中已经有记录了…