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

news2024/11/6 9:28:55

1.序列式容器与关联式容器

序列式容器
底层为线性序列的数据结构, 里面存储的是元素本身 。如vector/list/string/deque/forward_list。
关联式容器
也是用来存储数据的,于序列式容器不同的是, 里面存储的是<key,value>结构的键值对 ,在数据检索时比序列式容器效率高。如map/set/unordered_map/unordered_set。

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

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

2.set

set文档介绍

set底层是 二叉搜索树的K模型,map底层是 二叉搜索树的KV模型,关于二叉搜索树可以查看上篇 【二叉树进阶】二叉搜索树-CSDN博客

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

简单使用:

void test_set1()
{
	set<int> s;
	s.insert(1);
	s.insert(3);
	s.insert(4);
	s.insert(4);
	s.insert(5);
	//迭代器遍历
	set<int>::iterator it = s.begin();
	while (it != s.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;
	//范围for遍历
	for (auto& e : s)
	{
		cout << e << " ";
	}
	cout << endl;
    //拷贝构造
	set<int> copy(s);
	for (auto& e : copy)
	{
		cout << e << " ";
	}
}

可以看到,set具有排序+去重的效果,set底层就是搜索树,中序是有序的。

按从小到大顺序排序。

删除操作:

//1、使用迭代器方式删除
set<int>::iterator pos = s.find(40);
if (pos != s.end())
{
	s.erase(pos);
}
//2、直接删除
s.erase(40);
//3、使用算法里的find删除
set<int>::iterator pos = find(s.begin(),s.end(),40);
s.erase(pos);

说明:

使用迭代器方式删除,迭代器的位置必须是有效位置,否则,如果不检查,就会报错。

直接删除,值存在就删除,不存在就不删。

使用set自己的find和算法里的find有什么区别?

效率的问题。算法里的find效率是O(N),set底层是搜索树,find效率为O(log_2 N)。

算法里的find是用函数模板实现的,目的是让任何类型的迭代器都可以使用。

2.1set特点

1、set是K模型,主要用于查找“在不在”,特点就是快,因为底层是搜索树。

例如:

假设要把中国所有人的身份信息放进set中,查找一个人,只需要查找31次就可以了。

2^10*2^10*2^10~=2^30==10亿,2^31==20亿。

2、增、删、查时间复杂度为O(log_2 N)。

3、修改:不允许修改,因为修改就会破坏搜索树的结构。

2.2set应用举例

set为K模型,主要应用查找“在不在”的问题,这里举一个“简易字典”的例子。

在项目工程中,一般要求不展开std。(此示例下为没有展开std的写法)

简易字典:

void test_map2()
{
	std::map<std::string, std::string> dict;
	dict.insert(pair<std::string, std::string>("left", "左边"));
	dict.insert(pair<std::string, std::string>("sort", "排序"));
	dict.insert(pair<std::string, std::string>("string", "排序"));
	std::map < std::string, std::string>::iterator it = dict.begin();
	while (it != dict.end())
	{
		cout << it->first << ":" << it->second << endl;
		++it;
	}
	cout << endl;
}

按key的ASCII从小到大排序(走的是二叉树的中序为有序)。

3.map

map文档介绍

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

简单使用:

这样插入会报错。来看一下insert的说明。

 这里insert的参数是value_type& val,value_type就是pair。

再继续探索insert之前,就引入了键值对这一概念。

3.1键值对pair

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

SGI-STL中关于键值对的定义:

为什么map的insert参数要传pair呢?与它的遍历有关。

	map<int, int> m;
	m.insert(pair<int,int>(1, 1));
	m.insert(pair<int,int>(2, 2));
	m.insert(pair<int,int>(3, 3));
	m.insert(pair<int,int>(4, 4));
	//遍历
	map<int, int>::iterator it = m.begin();
	while (it != m.end())
	{
		cout << *it << " ";
        ++it;
	}
	cout << endl;

这种方式会报错,map中存有两个值,*it会返回两个值,C++是不允许一次返回两个值的,要返回两个值,把它们构成一个结构返回可以。

pair就相当于一个结构。*it返回的是一个pair,是一个key,value的结构体。

上述会报错的原因也就是*it是一个pair,自定义类型没有重载,不支持输出。

//正确遍历方式
while (it != m.end())
{
	cout << (*it).first << ":" << (*it).second << endl;
    //cout << it->first << ":" << it->second << endl;
	++it;
}

说明:

operator* 返回值是节点中值的引用,

operator-> 返回值是节点中值的指针,也就是pair<k,v>指针,这里"it->first"本应该是"it->->first",编译器为了可读性省略了一个"->"。

insert参数也可以用make_pair。

3.2make_pair

void test_map1()
{
	map<int, int> m;
	pair<int, int> a(0,0);
	m.insert(a);
	m.insert(pair<int,int>(1, 1));
	m.insert(pair<int,int>(2, 2));
	m.insert(pair<int,int>(3, 3));//pair构造函数,构造一个匿名对象
	m.insert(make_pair(5, 5));//函数模板构造一个pair对象
	//遍历
	map<int, int>::iterator it = m.begin();
	while (it != m.end())
	{
		cout << (*it).first << ":" << (*it).second << endl;
		++it;
	}
}

日常更喜欢用make_pair,因为不用声明模板参数,会自动推演。

3.3map应用举例

map为KV模型,根据Key找Value。这里举一个“查找水果次数”的例子。

查找水果次数:

示例方法一:

void test_map3()
{
	string strs[] = { "西瓜","苹果","西瓜","西瓜","西瓜","西瓜","苹果","樱桃" };
	map<string, int> countMap;
	for (auto& str : strs)
	{
		map<string, int>::iterator ret = countMap.find(str);
		if (ret != countMap.end())
		{
			ret->second++;
		}
		else
		{
			countMap.insert(make_pair(str, 1));
		}
	}
	for (auto& e : countMap)
	{
		cout << e.first << ":" << e.second << endl;
	}
}

3.4map的insert

依据map的应用举例,我们还要对map做进一步探索。

返回值是一个pair。

解释:

如果插入的值已经存在,则插入失败,iterator指向已经存在的元素,bool为false,

如果插入的值不存在,则插入,iterator指向新插入的元素,bool为true。

示例方法二:

void test_map3()
{
	string strs[] = { "西瓜","苹果","西瓜","西瓜","西瓜","西瓜","苹果","樱桃" };
	map<string, int> countMap;
	for (auto& str : strs)
	{
        //如果水果不在map中,直接插入。
        //如果水果在map中,通过返回值拿到水果所在节点的迭代器,++次数。
		pair<map<string, int>::iterator, int> ret = countMap.insert(make_pair(str, 1));
		if (ret.second == false)
		{
			ret.first->second++;
		}
	}
	for (auto& e : countMap)
	{
		cout << e.first << ":" << e.second << endl;
	}
}

这里,insert充当了两个作用,一个作用是查找,一个作用是插入。

3.5map的operator[]

这里operator[]是通过调用insert来实现的。

图文分析:

operator[]的作用就是给一个key,去查找key对应的value。

为什么这里不用find实现呢?

原因:假设用find,如果map中没有这个key,如何返回?

可以用抛异常,这里先不做讲解。

说明:

这里用insert:

1、如果key不在map中,则插入pair<key_type,mapped_type()>,mapped_type()为缺省值。(调用mapped_type类型的默认构造函数构造一个对象,若是int则为0,若是string则为空。),再返回key所在节点映射对象(mapped_type)的引用

2、如果key在map中,则插入失败,返回key所在节点映射对象(mapped_type)的引用

所以map中的operator[]有三层作用:

1、插入

2、查找key对应的映射对象

3、修改key对应的映射对象

示例方法三:

void test_map3()
{
	string strs[] = { "西瓜","苹果","西瓜","西瓜","西瓜","西瓜","苹果","樱桃" };
	map<string, int> countMap;
	//1、如果水果在map中,则operator[]会插入pair<str,0>,返回映射对象(次数)的引用,对它进行++。
	//2、如果水果不在map中,则operator[]会返回映射对象(次数)的引用,对它进行++。
	for (auto& str : strs)
	{
		countMap[str]++;
	}
	for (auto& e : countMap)
	{
		cout << e.first << ":" << e.second << endl;
	}
	countMap["香蕉"];//插入
	countMap["香蕉"] = 1;//修改
	cout << countMap["香蕉"] << endl;//查找
	countMap["猕猴桃"] = 3;//插入+修改
	for (auto& e : countMap)
	{
		cout << e.first << ":" << e.second << endl;
	}
}

map中,一般使用operator[]去完成:

1、插入+修改

2、修改

一般不会用他去查找,因为如果key不存在,会插入数据。

关于map的相关操作使用的接口:

1、增        insert+operator[]

2删        erase

3、查        find

4、改        operator[]

5、遍历     iterator+范围for

遍历出来的数据是按key来排序的,因为底层是搜索树,遍历走的是中序。

4.multiset和multimap

multiset文档介绍

multimap文档介绍

multiset和set的区别就在于multiset允许键值冗余。

void test_multi()
{
	multiset<int> s;
	s.insert(1);
	s.insert(2);
	s.insert(2);
	s.insert(2);
	s.insert(4);
	s.insert(3);
	for (auto& e : s)
	{
		cout << e << endl;
	}
}

查找相同元素查找的是按顺序排的第一个。

multimap和map的区别也是一样允许键值冗余。map中的key是唯一的,而multimap中key是可以重复的。

但是multimap没有operator[],因为对于相同的key,去查找value,不知道要找的是哪一个key对应的value,由于键值冗余,允许插入相同的,multimap的insert返回值也没有pair了。

关于multiset和multimap的其他接口都和set与map的接口相同。

5.在OJ中的使用

5.总结

此篇主要对set和map、multiset和multimap做了简单的理解和相关应用的举例。

关于其他的接口比较简单,由于和STL中vector、list、string等接口类似,这里没有做具体讲解,只做了特别的几个接口的说明。

遇事不决,一定要查文档。

关于set和map更深层次的探索,请看下篇。

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

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

相关文章

一文详解WebRTC、RTSP、RTMP、SRT

背景 好多开发者&#xff0c;希望对WebRTC、RTSP、RTMP、SRT有个初步的了解&#xff0c;知道什么场景该做怎样的方案选择&#xff0c;本文就四者区别做个大概的介绍。 WebRTC 提到WebRTC&#xff0c;相信好多开发者第一件事想到的就是低延迟&#xff0c;WebRTC&#xff08;W…

基于IntraWeb的数据表格的多选实现

基于IntraWeb的数据表格的多选实现 既可以单条操作&#xff0c;也可以多选操作。 delphi源代码。 BS开发Web网站开发&#xff0c;不需要安装服务器&#xff0c;Apache和IIS都不需要&#xff0c;自带企业级服务器。 运行exe服务器就架好了&#xff0c;直接打开手机浏览器或者…

技术成神之路:设计模式(十八)适配器模式

介绍 适配器模式&#xff08;Adapter Pattern&#xff09;是一种结构型设计模式&#xff0c;它允许接口不兼容的类可以协同工作&#xff0c;通过将一个类的接口转换成客户端所期望的另一个接口&#xff0c;使得原本由于接口不兼容而不能一起工作的类可以一起工作。 1.定义 适配…

防止错误输入!Excel单元格限制输入内容的三种有效方式

在Excel中&#xff0c;限制单元格输入内容可以帮助避免数据输入错误&#xff0c;确保数据的一致性和准确性。今天小编分享三种方法&#xff0c;可以轻松限制Excel单元格的输入内容&#xff0c;确保数据输入符合预期要求&#xff0c;一起来看看吧&#xff01; 方法一&#xff1a…

超声波清洗机哪家好用又实惠?2024热门超声波清洗机选择推荐!

经过长时间在眼镜清洁领域的深耕&#xff0c;超声波清洗技术已积累广泛用户群体的信任。市场虽繁荣&#xff0c;但也暴露出产品质量的多样性问题&#xff0c;特别是那些依赖营销手段走红的网络品牌或跨行业巨头&#xff0c;它们倾向于强化市场推广而忽视了核心技术的研发。这导…

AI日常绘画【国庆海报】:盛世迎华诞,Flux国庆节海报制作教程

大家好我是极可菌&#xff01;&#xff01;&#xff01; 马上就要到祖国母亲的节日了&#xff0c;想想心里都美滋滋的&#xff0c;终于可以放松一下了。相信AI绘画关于国庆主题肯定也会精彩纷呈吧&#xff0c;今天和大家分享几组关于国庆海报的制作教程。 本文使用基于Flux的相…

一款好用的图像处理软件:Photoshop

Photoshop 常被简称为PS&#xff0c;是图像处理领域里最常用也是很重要的一个工具。在平面广告设计、印刷出版等各领域有有着重要的作用。利用Photoshop图像处理软件&#xff0c;可以设计制作报纸、杂志、书籍、招贴广告、海报、建筑效果图、网页等各种精美的作品&#xff0c;普…

基于大数据技术的共享单车数据分析与辅助管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

mybatis-plus ==> 入门教程

文章目录 为什么要学呢&#xff1f;注意事项 简单入门案例配置日志雪花算法更改 ID 的方法 CRUD插入&#xff08;不解释了&#xff0c;代码非常简单&#xff09;更新查询&#xff08;批量查询&#xff09;按条件查询分页查询删除&#xff08;批量、通过条件、逻辑删除&#xff…

汇川AM400脉冲速度轴(轴控功能块ST源代码)

1、汇川AM400脉冲轴位置控制功能块 汇川AM400脉冲轴控制(轴控功能块ST源代码)-CSDN博客文章浏览阅读292次。汇川AM400电子齿轮指令详细应用介绍(CODESYS ST代码)_汇川plc am400 案例-CSDN博客文章浏览阅读146次。本文介绍了在使用汇川AM400电子齿轮指令前需要理解的比例随动概…

【SQLite】基础操作

数据查询 SELECT 查询所有数据 SELECT *FROM tableName使用AND操作符 SELECT * FROM tableName WHERE id=? AND name=?使用OR操作符 SELECT * FROM tableName WHERE id=? OR name=?组合使用AND和OR SELECT * FROM tableName WHERE (id=? AND name=?) OR status=?多表查询…

Python基础知识---入门概念

有些人不属于自己&#xff0c;但是遇见了也弥足珍贵。 -- 青山刚昌 《名侦探柯南》 安装python解释器 下载官网&#xff1a; Welcome to Python.org 安装pycharm编辑器 下载官网&#xff1a;Download PyCharm: The Python IDE for data science and web development by Je…

基于大数据的二手电子产品需求分析及可视化系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

ARM Process state -- SPSR

Holds the saved process state for the current mode. 保存当前模式的已保存进程状态。 N, bit [31] Set to the value of PSTATE.N on taking an exception to the current mode, and copied to PSTATE.N on executing an exception return operation in the current mod…

项目:微服务即时通讯系统客户端(基于C++QT)]四,中间界面搭建和逻辑准备

四&#xff0c;中间界面搭建 前言:当项目越来越复杂的时候&#xff0c;或许画草图是非常好的选择 一&#xff0c;初始化中间窗口initMidWindow void mainWidget::initMidWindow() {//使用网格布局进行管理QGridLayout* layout new QGridLayout();//距离上方 20px 的距离&…

QT开发:深入掌握 QtGui 和 QtWidgets 窗口管理:QMainWindow、QDialog 和 QWidget 的高级应用

目录 引言 1. QMainWindow&#xff1a;高级窗口类 基本结构 菜单栏、工具栏和状态栏 菜单栏 工具栏 状态栏 中心部件和可停靠窗口 中心部件 可停靠窗口 示例代码与详解 2. QDialog&#xff1a;对话框窗口类 模态和非模态对话框 模态对话框 非模态对话框 自定义…

「Java开发指南」如何用MyEclipse为iPhone搭建Spring应用程序?

本教程将引导您完成在iPhone上使用的软件组件生成&#xff0c;这就产生了一个完全实现的可运行iPhone应用程序&#xff0c;可以立即用于验证和测试生成的iPhone组件。在本教程中&#xff0c;您将学习如何&#xff1a; 从数据库表搭建到现有项目部署应用程序 MyEclipse v2024.…

点云配准ICP算法笔记

参考&#xff1a;【PCL】—— 点云配准ICP(Iterative Closest Point)算法_icp点云配准-CSDN博客 点云配准 计算出两个点云簇之间的变换矩阵&#xff0c;从而计算出位姿等信息&#xff0c;学习点云配准的目的是想要计算相邻两帧物体的点云之间的变换位姿&#xff0c;从而得到物…

企业合规新动力:天锐股份助力等保制度落地实施

等保是指对网络&#xff08;含信息系统、数据&#xff09;实施分等级保护、分等级监管&#xff0c;对网络中使用的网络安全产品实行按等级管理&#xff0c;对网络中发生的安全事件分等级响应、处置。 【地址&#xff1a;点击了解天锐股份数据安全产品】 等保的必要性 频发的网…

选择国企eHR人事管理系统的时候,应该注意什么?

近年来&#xff0c;中国正步入高速发展的黄金时期&#xff0c;国有企业&#xff08;国企&#xff09;在追求效率和管理水平提升方面迈出了重要步伐。为了进一步实现数字化、流程化和科学化管理&#xff0c;越来越多的国企选择引进eHR&#xff08;电子人力资源管理&#xff09;系…