【C++】STL — map和set的介绍 + 使用

news2024/11/24 1:17:15

文章目录

  • 📖 前言
  • 1. 键值对的引入⚡
  • 2. 树形结构的关联式容器🌟
  • 3. set的介绍 + 使用⭐
  • 4. map的介绍 + 使用⭐
    • 🏁4.4.1 利用map统计次数:
    • 🏁4.4.2 std::map::operator[]

📖 前言

本章将继续学习STL中的两个很重要的容器map和set,其底层实现是封装了一个红黑树,我们通过本节来学习和深入了解一下这两大容器……🙋 🙋 🙋 🙋 🙋

前情回顾:红黑树模拟实现 👉 传送门


1. 键值对的引入⚡

在之前的红黑树和AVL树的模拟实现中的Kye_value模型,我们都用到过pair,下面正式引入:

用来表示具有一 一对应关系的一种结构,该结构中一般只包含两个成员变量key和value,key代
表键值,value表示与key对应的信息。

例如我们之前提到过的,要建立一个英汉互译的字典,英文单词与其中文含义是一 一对应的关系。

在这里插入图片描述
它实际上是一个类模板,STL原码库中给出的源代码如下:

在这里插入图片描述

2. 树形结构的关联式容器🌟

序列式容器:

在前期我们所学过的STL容器中,例如:string,vector,list,queue…,这些序列式容器中我们不难发现,其存储的都是 C++ 基本数据类型(诸如 int、double、float、string等)或使用自定义类型(结构体)的元素。

关联式容器:
关联式容器则和序列式容器有很大区别,关联式容器也是用来存储数据的,与序列式容器不同的是,其里面存储的是<key, value>结构的键值对,在数据检索时比序列式容器效率更高。除此之外,序列式容器中存储的元素默认都是未经过排序的,而使用关联式容器存储的元素,默认会根据各元素的键值的大小做升序排序


3. set的介绍 + 使用⭐

使用 set 容器,必须引入该头文件#include < set >

set使用文档

在这里插入图片描述

  • T: set中存放元素的类型,实际在底层存储<value, value>的键值对。
  • Compare:set中元素默认按照小于来比较
  • Alloc:set中元素空间的管理方式,使用STL提供的空间配置器管理

set的插入:
在这里插入图片描述
与之前学习的容器中用到的接口类似,set也同样提供了插入接口。

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

	//如果已经存在则不插入 -- 排序 + 去重

	set<int>::iterator it = s.begin();
	while (it != s.end())
	{
		//*it = 10; const 迭代器和普通迭代器都不支持修改
		//STL官方库中也是一样的,也是用同一个,只是上层封装名字不一样

		cout << *it << " ";
		it++;
	}
	cout << endl;

	//底层也是迭代器
	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;

	set<int>::iterator pos = s.find(2);//〇(logN)
	if (pos != s.end())
	{
		cout << "set.find()找到了" << endl;
	}

	pos = find(s.begin(), s.end(), 2);//〇(N) -- 暴力查找
	if (pos != s.end())
	{
		cout << "找到了" << endl;
	}
}

运行结果:
在这里插入图片描述
set实现了去重和排序:

  • 有重复的不插入
  • 默认按照升序排列

同样的迭代器的使用方式也一样,只是这里的const迭代器和普通迭代器都是一样的,都不支持修改,原因是如果对二叉搜索树进行修改的话,很有可能会导致整棵树的结构被打乱,所以不支持修改。

set自带的查找和算法库中的查找有什么区别

  • set自带的查找是利用了搜索树的特点,查找时间复杂度为〇(logN)
  • 如果用算法库中的查找则是通过暴力查找的方式进行的,时间复杂度为〇(N)

set的删除:

在这里插入图片描述
虽然我们在实现红黑树的时候因为红黑树的删除过于复杂并没有实现,但是官方库中也为我们提供了相应的接口。

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

	s.erase(3);//直接给值删除

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

	int x;
	while (cin >> x)
	{
		set<int>::iterator pos = s.find(x);
		if (pos != s.end())
		{
			s.erase(pos);//迭代器删除
			cout << "删除" << x << "成功" << endl;
		}
		else
		{
			cout << x << "不在set中" << endl;
		}

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

在这里插入图片描述
还有其他的一些接口,有了之前容器的经验,自学起来很方便。

计算某一个值出现的次数:

在这里插入图片描述
对某一区间的值进行操作处理:
在这里插入图片描述***

4. map的介绍 + 使用⭐

使用 map 容器,必须引入该头文件#include < map >

map使用文档

在这里插入图片描述

  • key: 键值对中key的类型
  • T: 键值对中value的类型
  • Compare: 比较器的类型,map中的元素是按照key来比较的,缺省情况下按照小于来比
    较,一般情况下(内置类型元素)该参数不需要传递,如果无法比较时(自定义类型),需要用户
    自己显式传递比较规则(一般情况下按照函数指针或者仿函数来传递)
  • Alloc:通过空间配置器来申请底层空间,不需要用户传递,除非用户不想使用标准库提供的
    空间配置器

map的插入:

在这里插入图片描述
map插入的是一对键值对:

void test_map1()
{
	map<string, string> dict;
	//匿名对象的好处
	dict.insert(pair<string, string>("sort", "排序"));

	//不用匿名对象
	pair<string, string> kv("insert", "插入");
	dict.insert(kv);

	//make_pair是函数模板
	dict.insert(make_pair("left", "左边"));

	//可以这么写但是别这么用(隐式类型的转换) -- C++11再讲
	dict.insert({ "right", "右边" });

	//map的遍历
	map<string, string>::iterator it = dict.begin();
	while (it != dict.end())
	{
		//cout << *it << endl;//it->operator*() -- C++不支持返回两个值
		//cout << (*it).first << ":" << (*it).second << endl;

		cout << it->first << ":" << it->second << endl;

		it++;
	}
	cout << endl;

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

因为C++不支持返回两个值,所以我们这里用到了pair,通过pair的first和second,即可访问到两个值。

在这里插入图片描述
同时,map迭代器的使用方法和其他容器迭代器的使用方法一样,这是STL设计时为了方便使用,所采用的高维度泛型设计。

Key_value模型中,修改不能修改key,但是可以修改value。

🏁4.4.1 利用map统计次数:

如下是利用map来统计各种水果的次数:

通过查找来挨个遍历查找统计个数

void test_map2()
{
	string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果",
					 "西瓜", "苹果", "香蕉", "苹果", "香蕉" };

	map<string, int> countMap;
	for (auto& str : arr)
	{
		map<string, int>::iterator it = countMap.find(str);
		if (it != countMap.end())
		{
			it->second++;
		}
		else
		{
			countMap.insert(make_pair(str, 1));
		}
	}
}

在这里插入图片描述
注意:

  • 只要是一对一对的值都可以用pair
  • first和second是不允许被修改的

insert的返回值是一个pair,pair的first是一个迭代器(如果插入成功了指向新插入的位置,如果插入失败了,则返回已经存在的结点的位置),pair的second的一个bool值,插入成功是返回true,失败是返回false。

所以我们还可以通过返回值来统计个数

在这里插入图片描述

🏁4.4.2 std::map::operator[]

下面提供一种特殊的方式来统计次数:

map::operator[]

  • 在之前学习的容器中,operator[]都有随机访问的意思,这里的方括号已经没有了随机访问的意思
  • 这里operator[]的参数是key,返回值是value的引用

在这里插入图片描述
std::map::operator[]有自己的独特之处

上图红框画出来的部分可以理解为如下:

在这里插入图片描述
于是便有了如下的统计次数方式:
在这里插入图片描述
因为返回的是value的引用所以,可以修改,这样一来,operator[]兼顾了两个功能:插入 + 修改

同样当map需要插入的时候,也就有了如下的写法:

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

	//pair构造函数
	dict.insert(pair<string, string>("sort", "排序"));
	pair<string, string> kv("insert", "插入");
	dict.insert(kv); 

	//make_pair
	auto ret1 = dict.insert(make_pair("left", "左边"));
	auto ret2 = dict.insert(make_pair("left", "剩余"));

	dict["operator"] = "重载"; //插入 + 修改
	dict["left"] = "左边、剩余"; //修改
	dict["erase"];  //插入

	cout << dict["left"] << endl; //查找

	//遍历
	//map<string, string>::iterator it = dict.begin();
	auto it = dict.begin();
	while (it != dict.end())
	{
		//cout << *it << " ";
		//cout << (*it).first << ":" << (*it).second << endl;
		cout << it->first << ":" << it->second << endl;
		++it;
	}
	cout << endl;

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

在这里插入图片描述

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

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

相关文章

23.2.2打卡 2023牛客寒假算法基础集训营5 ABCDHKL 最详细的一集

A 这题据说可以贪心写 我为了省事直接upper二分第一个大于x的商品然后向前遍历完事 /* ⣿⣿⣿⣿⣿⣿⡷⣯⢿⣿⣷⣻⢯⣿⡽⣻⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣇⠸⣿⣿⣆⠹⣿⣿⢾⣟⣯⣿⣿⣿⣿⣿⣿⣽⣻⣿⣿⣿⣿⣿⣿⣿ ⣿⣿⣿⣿⣿⣿⣻⣽⡿⣿⣎⠙⣿⣞⣷⡌⢻⣟⣿⣿⣿⣿⣿⣿⣿…

使用动态创建pinia时报injection “Symbol(pinia)“ not found

前阵发现项目内用pinia报了injection "Symbol(pinia)" not found这个错误&#xff0c;因为前一阵用并没有这个问题。问了相关同事后发现是他新建了节点后调用的&#xff0c;导致的问题。 出现的警告如下图&#xff1a; 这问题排除了比较久&#xff0c;为什么呢&…

python自动化办公--pyautogui控制鼠标和键盘操作

在公司某些工作场景下&#xff0c;需要大量重复的工作&#xff0c;重复的工作完全可以通过python软件的自动化实现&#xff0c;省时省力。本文分享python自动化办公的利器之一--pyautogui&#xff0c;通过pyautogui可以轻松控制鼠标和键盘操作。 PyAutoGUI是一个纯Python的GUI自…

纯滞后系统的大林控制算法

大林控制算法原理早在1968年&#xff0c;美国IBM公司的大林&#xff08;Dahlin&#xff09;就提出了一种不同于常规PID控制规律的新型算法&#xff0c;即大林算法。该算法的最大特点是将期望的闭环响应设计成一阶惯性加纯延迟&#xff0c;然后反过来得到能满足这种闭环响应的控…

Linux服务器之间设置共享目录

前言有时候我们需要在两台linux服务器之间共享资源&#xff0c;例如在服务器A上面部署了一个大文件上传程序&#xff0c;但是需要将文件上传到服务器B的某个目录下面&#xff0c;因为上传大文件&#xff0c;需要先将文件所有分块单独上传到服务器B&#xff0c;然后在服务器B上面…

数字文档管理解决财务部门哪些常见问题?

如今&#xff0c;会计部门实施文档管理和自动化工作流程系统至关重要。这些组织要么缺乏数字系统&#xff0c;要么没有充分利用其文档管理解决方案的潜力。 数字文档管理解决财务部门哪些常见问题&#xff1f; 1.错过提前付款折扣&#xff1a;供应商经常为提前付款提供折扣&am…

虹科教您 | 浅谈现代GNSS模拟中的软件定义架构

随着技术的迭代更新&#xff0c;GPS/GNSS模拟技术也在不断发展进步。在过去&#xff0c;想要进行GNSS仿真基本上只有一种选择&#xff1a;使用固定式或分配式的硬件进行模拟。而如今&#xff0c;带来颠覆性创新的新型软件定义架构正在迅速取代传统的定制架构&#xff0c;这种独…

EvilnoVNC:一款针对组织安全与安全意识培训的网络钓鱼平台

关于EvilnoVNC EvilnoVNC是一款针对组织安全与安全意识培训的网络钓鱼平台&#xff0c;该工具开箱即用&#xff0c;可以帮助各大企业组织对内部员工进行安全意识培训&#xff0c;而且也可以帮助广大研究人员测试和研究网络钓鱼防御技术。 和其他网络钓鱼技术不同的不同之处在…

高并发秒杀的 常见的7种方案

高并发场景在现场的日常工作中很常见&#xff0c;特别是在互联网公司中&#xff0c;这篇文章就来通过秒杀商品来模拟高并发的场景。 本文环境&#xff1a; SpringBoot 2.5.7 MySQL 8.0 X MybatisPlus Swagger2.9.2 模拟工具&#xff1a; Jmeter 模拟场景&#xff1a; 减库…

2.5G网卡调试记录

2.5G网卡调试记录 下载驱动 去https://www.realtek.com/zh-tw/downloads这个网站下载2.5G USB网卡对应的驱动 编译驱动 Makefile中需要进入到内核目录/lib/modules/4.19.232/build中进行内核编译&#xff0c;但是我们的build文件链接已经失效了&#xff0c;并且源文件也删除…

力扣sql简单篇练习(八)

力扣sql简单篇练习(八) 1 修复表中的名字 1.1 题目内容 1.1.1 基本题目信息 1.1.2 示例输入输出 1.2 示例sql语句 # 考察的是字符串函数的用法 SELECT user_id,concat(upper(left(name,1)),lower(substr(name,2))) name FROM Users ORDER BY user_id asc1.3 运行截图 2 订单…

Qt TCP (小型聊天窗口)

实现的具体功能为&#xff1a; 服务器端需要主动监听&#xff0c;可以主动断开连接&#xff0c;可以发送信息给客户端客户端需要输入主机&#xff0c;端口号&#xff0c;需要主动连接&#xff0c;可以主动断开连接&#xff0c;可以发送信息给服务器端服务器端和客户端都能看到聊…

【C++算法图解专栏】一篇文章带你掌握差分算法

✍个人博客&#xff1a;https://blog.csdn.net/Newin2020?spm1011.2415.3001.5343 &#x1f4e3;专栏定位&#xff1a;为 0 基础刚入门数据结构与算法的小伙伴提供详细的讲解&#xff0c;也欢迎大佬们一起交流~ &#x1f4da;专栏地址&#xff1a;https://blog.csdn.net/Newin…

hadoop.fs.FileSystem.get导致OOM的原因和解决方案

问题描述 在调用HDFS获取文件系统的get接口时&#xff0c;指定用户可能会导致OOM问题&#xff0c;示例代码如下&#xff1a; FileSystem fileSystem FileSystem.get(uri, conf, "hadoopuser");问题溯源 该方法源码&#xff1a; 在有缓存的情况下将从Cache中取&a…

Android 11 SystemUI(状态/导航栏)-状态栏下拉时图标的隐藏与通知面板的半透黑色背景

概述 本文续自:Android 11 的状态栏的隐藏 PS 本文虽然同属于SystemUI, 但目前并 没有 打算整理成专橍或撰写一个系列的想法. 仅仅为了记录一些过程, 留下那些容易被遗忘的点滴. 开始下拉时状态栏图标被隐藏 状态橍的图标在用户开始触摸(ACTION_DOWN)后, 会开始展开, 显示扩展…

答题小程序题目批量导入模板以及题库文本格式规范

近期又接到了一个知识竞赛的需求&#xff0c;在开发答题小程序的过程中&#xff0c;遇到了不少难题&#xff0c;但是都一一克服了。凭借多年的答题小程序开发经验&#xff0c;我总结了一下题目批量导入题库文本格式规范。一、答题小程序题目批量导入模板小程序【答题小博士】二…

《数字经济全景白皮书》后疫情时代数字化驱动增长洞察之赛道篇

易观分析&#xff1a;《数字经济全景白皮书》浓缩了易观分析对于数字经济各行业经验和数据的积累&#xff0c;并结合数字时代企业的实际业务和未来面临的挑战&#xff0c;以及数字技术的创新突破等因素&#xff0c;最终从数字经济发展大势以及各领域案例入手&#xff0c;帮助企…

面试之 Python 框架 Flask、Django、DRF

Django、flask、tornado 框架的比较 ★★★★★ Django&#xff1a;大而全的框架。它的内部组件比较多&#xff0c;如 ORM、Admin、中间件、Form、ModelForm、Session、缓存、信号、CSRF等&#xff0c;功能也都很完善。 flask&#xff1a;微型框架&#xff0c;内部组件就比较少…

JavaScript中的事件对象、事件对象的属性

一、什么是事件对象​ 1&#xff09;、 事件对象 就是保存着事件相关信息的对象。当事件发生时&#xff0c;会自动产生事件对象&#xff08;不需要new&#xff09;&#xff0c;事件对象中包含着&#xff1a;事件源&#xff08;发生事件的dom元素&#xff09;&#xff0c;点击是…

全网最详细的mybatis plus 条件构造器queryWrapper学习,比如and(),eq(),or(),like()等方法以及分页操作

文章目录1. 引言2. 结构关系3. 环境配置3.1 引入jar包3.2 创建数据源3.2 创建User实体类3.4 创建UserMapper类3.5 创建UserService类4. 操作演示5. 注意事项1. 引言 mybatis大家都有使用过&#xff0c;既面向对象又灵活可配。不友好的地方是&#xff0c;会随着使用出现大量xml…