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

前言
本章将继续学习STL中的两个很重要的容器map和set,其底层实现是封装了一个红黑树,我们通过本节来学习和深入了解一下这两大容器。。。
序列式容器: string 、Vector、List 、dequeue
关联式容器:MAP 、SET、nordered_map、unordered_set。
关联式容器也是用来存储数据的,与序列式容器不同的是,其里面存储的是**<key, value>结构的键值对**,在数据检索时比序列式容器效率更高。
除此之外,序列式容器中存储的元素默认都是未经过排序的,而使用关联式容器存储的元素,默认会根据各元素的键值的大小做升序排序。

目录

    • 1. 键值对的引入
    • 2. set的介绍 + 使用
      • 2.1 set的构造
      • 2.2 set的插入
      • 2.2 set的删除
    • 3. Map 的介绍 + 使用
      • 3.1 Map 的构造
      • 3.2 Map 的插入Insert
      • 3.3 利用map统计次数
      • 3.3 Map 遍历方式
      • 3.4 Map总结

1. 键值对的引入

用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量key和value,key代表键值,value表示与key对应的信息.
在这里插入图片描述
它实际是一个类模板,STL库中给出源代码如下:

template <class T1, class T2>
struct pair
{
typedef T1 first_type;
typedef T2 second_type;
T1 first;
T2 second;
pair(): first(T1()), second(T2())
{}
pair(const T1& a, const T2& b): first(a), second(b)
{}
};

2. set的介绍 + 使用

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

  1. Set是按照一定次序存储元素的容器
  2. Set中的元素不能在容器中修改(元素总是const),但是可以从容器中插入或删除它们
  3. 在set中,存放的是Value**(value就是key,类型为T),并且每个value必须是唯一的.**
  4. 在内部,set中的元素总是按照其内部比较对象(类型比较)所指示的特定严格弱排序准则进行排序
  5. Set容器通过key访问单个元素的速度通常比unordered_set容器慢,但它们允许根据顺序对子集进行直接迭代
  6. set在底层是用二叉搜索树(红黑树)实现的。

注意:(与MAP的区别)

  • 与map/multimap不同,set中只放 value,map 中存储的是真正的键值对<key, value>.
  • Set中插入元素时,只需要插入value即可,不需要构造键值对
  • set中的元素不可以重复(因此可以使用set进行去重)
  • 使用set的迭代器遍历set中的元素,可以得到有序序列

2.1 set的构造

在这里插入图片描述

  • T: set中存放元素的类型,实际在底层存储<value, value>的键值对。
  • Compare:set中元素默认按照小于来比较
  • Alloc:set中元素空间的管理方式,使用STL提供的空间配置器管理
#include <set>
void TestSet()
{
// 用数组array中的元素构造set
int array[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0, 1, 3, 5, 7, 9, 2, 4,
6, 8, 0 };
set<int> s(array, array+sizeof(array)/sizeof(array));
cout << s.size() << endl;

// 正向打印set中的元素,从打印结果中可以看出:set可去重
for (auto& e : s)
{
   cout << e << " ";
}
cout << endl;
}
//使用迭代器逆向打印set中的元素
for (auto it = s.rbegin(); it != s.rend(); ++it)
{
   cout << *it << " ";
   cout << endl;
}

2.2 set的插入

在这里插入图片描述
set自带的Find()和算法库中的Find()有什么区别

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

2.2 set的删除

在这里插入图片描述

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;
	}

3. Map 的介绍 + 使用

  • map是关联容器,它按照特定key的次序存储由键值key和值value组合而成的元素。
  • typedef pair<const key, T> value_type
  • 在内部,map中的元素总是按照键值key进行比较排序的.
  • map支持下标访问符,即在[ ]中放入key,就可以找到与key对应的value
  • map通常被实现为二叉搜索树((红黑树))
  • 统计value相同的次数时,使用[ ]操作符,见下面解释

使用 map 容器,必须引入该头文件#include < map >
在这里插入图片描述

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

3.1 Map 的构造

在这里插入图片描述

int main ()
{
  std::map<char,int> first;

  first['a']=10;
  first['b']=30;
  first['c']=50;
  first['d']=70;

  std::map<char,int> second (first.begin(),first.end());

  std::map<char,int> third (second);
 return 0;
 }

3.2 Map 的插入Insert

在这里插入图片描述

  • map插入的是一对键值对Pair<K ,v>
  • 通过pair的first和second,即可访问到两个值
  • Key_value模型中,修改不能修改key,但是可以修改value在这里插入图片描述

3.3 利用map统计次数

有两种方案:
(1)通过查找来挨个遍历查找统计次数
(2)使用operator [ ]来进行统计次数

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

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));
		}
	}
}

2.使用operator [ ]来进行统计次数

  • operator[]的参数是key,返回值是value的引用
  • operator[]都有随机访问的意思,这里的方括号已经没有了随机访问的意思
map<string,int> countMap;
for(auto&str:arr)
{
 //1.str不在countMap中,插入pair(str,int()),然后再对返回次数++;
 //2. str在countMap中,返回value(次数)的引用,次数++
     countMap[str]++;
}

对operator [ ]的讲解:

  • operator[]兼顾了两个功能:插入 + 修改
  • Map中有这个key,返回value的引用(查找、修改value)
  • Map中没有这个key,会插入一个pair(key,v());返回value的引用。(插入+修改)

模拟operator [ ]的实现代码:

v& operator[](const K&key)
{
    pair<iterator,bool> ret=insert(make_pair(key,v());
    return ret.first->second;
}
//STl库里面的实现
mapped_type& operator[](const key_type& k)
{
   return (*((this->insert(make_pair(k,mapped_type()))).first)).second;
}


3.3 Map 遍历方式

在这里插入图片描述

注意

  • sort不能对map进行排序,因为map不是随机迭代器
  • 在元素访问时,有一个与operator[]类似的操作at()(该函数不常用)函数,都是通过key找到与key对应的value然后返回其引用
  • 不同的是:当key不存在时,operator[]用默认value与key构造键值对然后插入,返回该默认value,at()函数直接抛异常。

3.4 Map总结

  • map中的的元素是键值对
  • map中的key是唯一的,并且不能修改
  • 默认按照小于的方式对key进行比较
  • map中的元素如果用迭代器去遍历,可以得到一个有序的序列
  • map的底层为平衡搜索树(红黑树),查找效率比较高 O ( l o g 2 N ) O(log_2 N) O(log2N)
  • 支持[]操作符,operator[]中实际进行插入查找

尾声
看到这里,相信大家对这个C++有了解了。
如果你感觉这篇博客对你有帮助,不要忘了一键三连哦

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

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

相关文章

成员函数构造函数析构函数

文章目录 类的6个默认成员函数构造函数概述定义特性 析构函数概述特性 类的6个默认成员函数 空类&#xff1a; 如果一个类里面什么都没有写&#xff0c;我们称之为空类 class Date {};空类真的什么都没有吗&#xff1f; 实际上并非如此&#xff0c;编译器会自动生成6个默认成…

【大数据】HDFS

文章目录 [toc]HDFS 1.0NameNode维护文件系统命名空间存储元数据解决NameNode单点问题 SecondaryNameNode机架感知数据完整性校验校验和数据块检测程序DataBlockScanner HDFS写流程HDFS读流程HDFS与MapReduce本地模式Block大小 HDFS 2.0NameNode HANameNode FederationHDFS Sna…

C++笔试强训day19

目录 1.小易的升级之路 2.礼物的最大价值 3.对称之美 1.小易的升级之路 链接 模拟就行&#xff0c;唯一可能是难点得就是gcd&#xff08;最大公约数&#xff09; #include <iostream> using namespace std; #define int long long const int N 1e5 10; int arr[N];…

【DIY小记】深圳万象天地餐馆探店点评

第一次在技术博客里面写生活日记&#xff0c;也算是破了个小天荒。个人以为&#xff0c;博客是个人生活思考的载体&#xff0c;而技术只占生活的一部分&#xff0c;那么博客里为什么一定要限制只能够写技术内容&#xff0c;不能写点其它生活上的东西呢&#xff1f;思来想去&…

科研诚信与学术规范 2024年春 期末考试答案

章节答案&#xff1a;https://www.bilibili.com/video/BV1JZ42177F8/ 是这个课&#xff0c;网上的大多数答案都是以前的&#xff0c;跟这门课没啥关系. 期末考试的答案长这样&#xff0c;题库有80个题&#xff0c;考试一般是50个题。 期末考试答案&#xff1a;&#xff08;不…

C++动态内存区域划分、new、delete关键字

目录 一、C/C中程序的内存区域划分 为什么会存在内存区域划分&#xff1f; 二、new关键字 1、内置类型的new/delete使用方法&#xff1a; 2、new和delete的本质 一、C/C中程序的内存区域划分 为什么会存在内存区域划分&#xff1f; 因为不同数据有不同的存储需求&#xff0…

6818Linux内核--Bootloader应用分析

Bootloader应用分析 一个嵌入式 Linux 系统从软件的角度看通常可以分为四个层次&#xff1a; 引导加载程序。包括固化在固件( firmware )中的 boot 代码(可选)&#xff0c;和 Boot Loader 两大部分。 Linux 内核。特定于嵌入式板子的定制内核以及内核的启动参数。 文件系统…

Polygon市值机器人

随着区块链技术的蓬勃发展和数字货币市场的日益繁荣&#xff0c;投资者们对于如何精准把握市场动态、实现资产稳健增长的需求愈发迫切。在这个背景下&#xff08;市值管理飞//机//aishutuyu&#xff09;&#xff0c;Polygon市值机器人应运而生&#xff0c;作为一款基于Polygon公…

TriCore:Interrupt

今天简单总结下 TriCore 的中断路由模块。 名词缩写 缩写全称说明IRInterrupt Router SRService Request 包括&#xff1a; 1. External Resource 2. Internal Resource 3.SW&#xff08;Software&#xff09; SPService Privoder 包括&#xff1a; 1. CPU 2. DMA SRNServic…

【5分钟学会一个知识点】01.Elasticsearch基本操作-增删改查

目录 【5分钟学会一个知识点-探索现代搜索与分析引擎的魅力】01.Elasticsearch基本操作-增删改查1.基本操作1.1索引操作1.2文档操作1.3查询1.4修改数据1.5查询1.5.1条件查询1.5.1.1遍历所有的索引1.5.1.2查询某个索引1.5.1.3条件查询1&#xff1a;使用GET url传参数1.5.1.4条件…

proteus数模转换器DAC0832的应用

proteus proteus&#xff0c;即EDA工具软件。Proteus软件是英国Lab Center Electronics公司出版的EDA工具软件。它不仅具有其它EDA工具软件的仿真功能&#xff0c;还能仿真单片机及外围器件。它是比较好的仿真单片机及外围器件的工具。虽然国内推广刚起步&#xff0c;但已受到…

油泼辣子在食品类别可以申请成商标不!

前阵韩国人在美国申请“chili crunch”油泼辣子作为商标&#xff0c;还准备禁止华人餐馆使用投诉侵权并索赔&#xff0c;普推知产老杨在USPTO上面检索发现&#xff0c;这个人申请的主要是30类方便食品的调味品&#xff0c;商标分类是全球通用的。 商标名称不能申请本类所属的通…

C++的数据结构(三):栈

栈&#xff08;Stack&#xff09;是一种后进先出&#xff08;LIFO, Last In First Out&#xff09;的数据结构&#xff0c;它只允许在一端&#xff08;称为栈顶&#xff09;进行插入和删除操作。栈的这种特性使得它在解决函数调用、括号匹配、表达式求值等问题时具有天然的优势…

Linux下多线程相关概念

thread 1.什么是线程1.1 线程优缺点1.2 线程异常1.3 线程用途 2. 进程和线程区别3. 线程控制3.1 POSIX线程库3.2 pthread_create()3.3 线程ID3.4 线程ID地址空间布局pthread_self() 3.5 线程终止pthread_exit函数pthread_cancle函数 3.6 线程等待3.7 分离线程__thread修饰全局变…

【安全每日一讲】加强数据安全保护 共享数字化时代便利

前言 数据安全是数据治理的核心内容之一&#xff0c;随着数据治理的深入&#xff0c;我不断的碰到数据安全中的金发姑娘问题&#xff08;指安全和效率的平衡&#xff09;。 DAMA说&#xff0c;降低风险和促进业务增长是数据安全活动的主要驱动因素&#xff0c;数据安全是一种资…

Django项目之电商购物商城 -- 修改/删除收货地址/设置默认地址

Django项目之电商购物商城 – 修改/删除收货地址/设置默认地址 修改和删除收货地址依旧实在user应用下进行 , 其思路和新增收货地址非常相似 依旧是更具前端的数据来写 在这里修改和删除地址的URL是相同的 , 所以我们只要设置一个模型类就可以实现这两个功能 一 . 修改地址…

apk反编译修改教程系列-----反编译apk 去除软件强制更新的八种方式步骤解析【十七】

安卓有的apk 软件会不断更新。但有些用户需要旧版的有些功能或者新版功能增减原因等等。需要不更新继续使用。这类问题有的可以简单修改版本号来跳过更新。或者有的软件可以忽略。但对于某些无法跳过更新界面等等的apk。就需要深度反编译来去除软件的强制更新。 通过课程可以了…

Obsidian/Typora设置图床

在obsidian中默认图片是保存在本地的&#xff0c;但是在要导出文档上传到网上时&#xff0c;由于图片保存在本地&#xff0c;会出现无法加载图片的问题。 这里引用的一段话&#xff1a; 这里使用picgo-core和gitee实现图床功能&#xff0c; 参考1&#xff1a; Ubuntu下PicGO配…

【Docker】Ubuntu下Docker的基本使用方法与常用命令总结

【Docker】docker的基本使用方法 镜像image与容器container的关系基本命令- 查看 Docker 版本- 拉取镜像- 查看系统中的镜像- 删除某个镜像- 列出当前 Docker 主机上的所有容器&#xff0c;包括正在运行的、暂停的、已停止的&#xff0c;以及未运行的容器- 列出当前 Docker 主机…