当前位置: 首页 > news >正文

【C++进阶04】STL中map、set、multimap、multiset的介绍及使用

在这里插入图片描述

一、关联式容器

vector/list/deque…
这些容器统称为序列式容器
因为其底层为线性序列的数据结构
里面存储的是元素本身

map/set…
这些容器统称为关联式容器
关联式容器也是用来存储数据的
与序列式容器不同的是
其里面存储的是<key, value>结构的键值对
在数据检索时比序列式容器效率更高

二、键值对

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

现在要建立一个英汉互译的字典
那该字典中必然有英文单词与其对应的中文含义
而且,英文单词与其中文含义是一一对应的关系
即通过该应该单词,在词典中就可以找到与其对应的中文含义

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

三、set

3.1 树形结构的关联式容器

根据应用场景的不同
C++STL总共实现了
两种不同结构的管理式容器:树型结构与哈希结构
树型结构的关联式容器主要有四种:
map、set、multimap、multiset
底层都是使用平衡搜索树(红黑树)来实现
容器中的元素是一个有序的序列

3.2 set的介绍

  1. set是按照一定次序存储元素的容器
    与map/multimap不同的是
    map/multimap中存储的是真正的键值对<key, value>
    set中只放value,但在底层实际存放的是由<value, value>构成的键值对

  2. 在set中,元素是唯一的
    元素的value就是key,类型为T
    set元素可以插入或删除,但不能修改
    map不能修改key,但可以修改value值
    set中插入元素时,只需要插入value即可,不需要构造键值对

  3. set中的元素总是按内部比较对象(类型比较)
    默认按照小于来比较
    所指示的特定“严格弱排序”准则进行排序
    使用set的迭代器遍历set中的元素,可以得到有序序列

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

  5. set中查找某个元素,时间复杂度为: l o g 2 n log_2 n log2n

set中的元素之所以不允许修改是怕破坏搜索规则

3.3 set的定义及使用

set的定义

set<int> s1; // 构造int类型的空容器set<int> s2(s1); // 拷贝构造string str("abcd");
set<char> s3(str.begin(), str.end()); // 迭代器构造某段区间set<int, greater<int>> s4; // 比较方式改为大于 

set的各个接口跟之前学的vector、list差不多
就不多介绍
set的使用

void test_set()
{set<int> s;// 插入元素并去重s.insert(1);s.insert(1);s.insert(2);s.insert(1);s.insert(2);s.insert(3);s.insert(4);s.insert(3);// 搜索树不允许修改key,可能会破坏搜索的规则// 1. 迭代器遍历容器set<int>::iterator it = s.begin();while (it != s.end()){cout << *it << " ";it++;}cout << endl;// 2. 范围for遍历容器for (auto e : s){cout << e << " ";}cout << endl;// 删除元素s.erase(1);// 查找删除set<int>::iterator pos = s.find(2);if (pos != s.end())s.erase(pos);// 计算容器中值为3的元素cout << s.count(3) << endl;// 清空容器s.clear();// 交换两个容器的数据set<int> tmp{ 5, 7, 9 };s.swap(tmp);
}// 输入一个值,查找在不在
void test_set2()
{set<int> s;s.insert(1);s.insert(1);s.insert(2);s.insert(1);s.insert(2);s.insert(3);s.insert(3);s.insert(3);int x;while (cin >> x){/*set<int>::iterator it = s.find(x);if (it != s.end()){cout << "在" << endl;}else{cout << "不在" << endl;}*/if (s.count(x)){cout << "在" << endl;}else{cout << "不在" << endl;}}
}

multiset 允许冗余,其他跟set还是一样的

void test_set3()
{multiset<int> s;s.insert(1);s.insert(1);s.insert(2);s.insert(1);s.insert(2);s.insert(3);s.insert(3);s.insert(3);for (auto e : s){cout << e << " ";}cout << endl;// 有多个key,find找中序的第一个key
}

四、map

4.1 map的介绍

  1. map是关联容器,它按照特定的次序(按照key来比较)存储由键值key和值value组合而成的元
    素,使用迭代器遍历map中的元素,可以得到一个有序序列

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

  3. map容器中的键值key不能修改,但元素值value可以修改
    因为map底层是根据每个元素的键值key构建的

  4. 在内部,map中的元素总是按照键值key进行比较排序的
    不传内部比较对象时,map中元素键值key默认按小于比较

  5. map中通过键值访问单个元素的速度通常比unordered_map容器慢,但map允许根据顺序
    对元素进行直接迭代

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

  7. map的底层是平衡二叉搜索树(红黑树)
    map查找某个元素时间复杂度为 l o g N log N logN

4.2 map的定义及使用

map的定义

// 构造一个key为string,value为char的容器
map<string, char> m1; // 构造一个跟m1一样的容器
map<string, char> m2(m1);// 迭代器构造m2的某段区间的容器
map<string, char> m3(m2.begin(), m2.end());// key的比较方式改成大于
map<string, char, greater<string>> m4; 

map的插入和删除
在这里插入图片描述
value_type是pair的别名

typedef pair<const key, T> calue_type;

因此插入时需要构造一个pair的匿名对象

void test_map()
{map<string, string> dict;// 构造一个pair的匿名对象去插入dict.insert(pair<string, string>("int", "整型")); // 用pair代码会很长,更常用的是make_pair// make_pair是一个函数模板,能通过传参自动推导类型dict.insert(make_pair("sort", "排序")); dict.insert(make_pair("string", "字符串"));dict.insert(make_pair("count", "计数"));// 已经有的key,会插入失败dict.insert(make_pair("count", "(计数)")); // map<string, string>::iterator dit = dict.begin();auto dit = dict.begin();while (dit != dict.end()){// 直接*dit无法通过编译.C++不支持返回两个值// dit解引用后是一个pair的结构体,里面有两个值,并不支持流插入// cout << (*dit).first << ":" << (*dit).second << endl;cout << dit->first << ":" << dit->second << endl; // 结构体里的指针一般用箭头dit++;}cout << endl;// 根据key值删除dict.erase(string);//迭代器删除map<string, string>::iterator pos = dict.find(sort);if (pos != dict.end())dict.erase(pos);
}

insert的返回值是pair
pair第一个成员是map的迭代器类型
第二个成员是bool类型

  • 若插入元素的键值key在map中不存在
    insert插入成功,并返回插入后元素的迭代器和true
  • 若插入元素的键值key在map中已存在
    则insert插入失败,并返回map中键值为key元素的迭代器和false

map的operator[ ]
在这里插入图片描述
operator[ ] 的返回值
在这里插入图片描述
[ ]operator实现的逻辑分为以下3个步骤:

  1. 调用insert函数插入键值对
  2. 拿出从insert函数获取到的迭代器
  3. 返回该迭代器位置元素的值value

代码分解

mapped_type& operator[] (const key_type& k)
{//1. 调用insert函数插入键值对pair<iterator, bool> ret = insert(make_pair(k, mapped_type()));//2. 拿出从insert函数获取到的迭代器iterator it = ret.first;//3. 返回该迭代器位置元素的值valuereturn it->second;
}

[ ]的插入、修改、查找、插入+修改
以及统计水果出现的次数

void test_map2()
{string arr[] = { "苹果", "香蕉", "西瓜", "梨子", "香蕉", "西瓜", "西红柿", "香蕉", "西瓜", "苹果", "西红柿" };map<string, int> countMap;//for (auto e : arr) // 统计水果出现次数//{//	map<string, int>::iterator it = countMap.find(e);//	if (it == countMap.end())//	{//		countMap.insert(make_pair(e, 1));//	}//	else//	{//		it->second++;//	}//}for (auto& e : arr) // 方括号统计水果出现次数{countMap[e]++; // [] 的三个功能: 插入、修改、查找、插入+修改}for (auto& kv : countMap){cout << kv.first << ":" << kv.second << endl; // 结构体里的指针一般用箭头}cout << endl;}// countMap[e]++; 这段代码底层实现
// V& operator[](const K& key)
// {
// 	pair<iterator, bool> ret = insert(make_pair(key, V()));
// 	return ret.first->second;
//}void test_map3()
{map<string, string> dict;dict.insert(make_pair("sort", "排序"));dict.insert(make_pair("string", "字符串"));dict.insert(make_pair("count", "计数"));dict.insert(make_pair("count", "(计数)"));dict["left"]; // 插入dict["right"] = "右"; // 插入+修改dict["string"] = "(字符串)"; // 修改cout << dict["string"] << endl; // 查找cout << dict["endl"] << endl; // 查找auto dit = dict.begin();while (dit != dict.end()){cout << dit->first << ":" << dit->second << endl; dit++;}cout << endl;
}

[ ]operator的返回值是key的value的引用
所以我们对该函数返回值的修改
实际就是对键值key的value的修改

multimap
multimap跟map基本一样
只是multimap允许键值冗余
find返回值是返回搜索树中序第一个键值
为key的元素的迭代器

由于冗余,调用operator[ ]时
返回键值应为哪个key的value引用
而存在歧义,因此multimap没有operator[ ]接口

如果支持迭代器就一定支持范围for
因为范围for的底层就是迭代器

五、map和set的区别

  1. map元素是key-value(关键字-值)对
    set元素是关键字
    map和set都不允许插入重复关键字

  2. set迭代器是const
    所以不允许修改元素值
    map可以修改value,但不能修改key
    map和set底层红黑树依靠关键字保持有序性
    所以不允许修改关键字

  3. map支持下标操作,set则不支持
    注意:map下标通过insert实现
    也就是尝试插入一个查询键值对
    如果存在则返回该键值对

✨✨✨✨✨✨✨✨
本篇博客完,感谢阅读🌹
如有错误之处可评论指出
博主会耐心听取每条意见
✨✨✨✨✨✨✨✨

相关文章:

【C++进阶04】STL中map、set、multimap、multiset的介绍及使用

一、关联式容器 vector/list/deque… 这些容器统称为序列式容器 因为其底层为线性序列的数据结构 里面存储的是元素本身 map/set… 这些容器统称为关联式容器 关联式容器也是用来存储数据的 与序列式容器不同的是 其里面存储的是<key, value>结构的键值对 在数据检索时…...

在 Linux 中开启 Flask 项目持续运行

在 Linux 中开启 Flask 项目持续运行 在部署 Flask 项目时&#xff0c;情况往往并不是那么理想。默认情况下&#xff0c;关闭 SSH 终端后&#xff0c;Flask 服务就停止了。这时&#xff0c;您需要找到一种方法在 Linux 服务器上实现持续运行 Flask 项目&#xff0c;并在服务器…...

考研个人经验总结【心理向】

客官你好 首先&#xff0c;不管你是以何种原因来到这篇博客&#xff0c;以下内容或多或少可能带给你一些启发。如果你还是大二or大三学生&#xff0c;有考研的打算&#xff0c;不妨提前了解一些考研必备的心理战术&#xff0c;有时候并不是你知识学得不好&#xff0c;而是思维…...

如何在CentOS安装SQL Server数据库并通过内网穿透工具实现公网访问

文章目录 前言1. 安装sql server2. 局域网测试连接3. 安装cpolar内网穿透4. 将sqlserver映射到公网5. 公网远程连接6.固定连接公网地址7.使用固定公网地址连接 前言 简单几步实现在Linux centos环境下安装部署sql server数据库&#xff0c;并结合cpolar内网穿透工具&#xff0…...

jupyter内核错误

1、在dos窗口输入以下命令激活环境&#xff1a;anaconda activate 【py环境名&#xff0c;比如py37】&#xff08;目的是新家你一个虚拟环境&#xff09; 2、在虚拟环境py37下安装jupyter notebook&#xff0c;命令&#xff1a;pip install jupyter notebook 3、安装ipykerne…...

设计模式的艺术P1基础—2.3 类之间的关系

设计模式的艺术P1基础—2.3 类之间的关系 在软件系统中&#xff0c;类并不是孤立存在的&#xff0c;类与类之间存在各种关系。对于不同类型的关系&#xff0c;UML提供了不同的表示方式 1&#xff0e;关联关系 关联&#xff08;Association&#xff09;关系是类与类之间最常用…...

工业无人机行业研究:预计2025年将达到108.2亿美元

近年来&#xff0c;在技术进步和各行各业对无人驾驶飞行器 (UAV) 不断增长的需求的推动下&#xff0c;工业无人机市场一直在快速增长。该市场有望在未来几年继续其增长轨迹&#xff0c;许多关键趋势和因素推动其发展。 在全球范围内&#xff0c;工业无人机市场预计到 2025 年将…...

PCA主成分分析算法

在数据分析中&#xff0c;如果特征太多&#xff0c;或者特征之间的相关性太高&#xff0c;通常可以用PCA来进行降维。比如通过对原有10个特征的线性组合, 我们找出3个主成分&#xff0c;就足以解释绝大多数的方差&#xff0c;该算法在高维数据集中被广泛应用。 算法&#xff08…...

Hyperledger Fabric 权限策略和访问控制

访问控制是区块链网络十分重要的功能&#xff0c;负责控制某个身份在某个场景下是否允许采取某个操作&#xff08;如读写某个资源&#xff09;。 常见的访问控制模型包括强制访问控制&#xff08;Mandatory Access Control&#xff09;、自主访问控制&#xff08;Discretionar…...

Day28 回溯算法part04 93. 复原IP地址 78. 子集 90. 子集 II

回溯算法part04 93. 复原IP地址 78. 子集 90. 子集 II 93. 复原 IP 地址 class Solution { private:vector<string> result;bool isValid(string& s,int start,int end){if (start > end) return false;if (s[start] 0 && start ! end) { // 0开头的数…...

Linux系统常用的安全优化

环境&#xff1a;CentOS7.9 1、禁用SELinux SELinux是美国国家安全局对于强制访问控制的实现 1)永久禁用SELinux vim /etc/selinux/config SELINUXdisabled #必须重启系统才能生效2&#xff09;临时禁用SELInux getenforce #查看SELInux当前状态 setenforce 0 #数字…...

Vue-4、单向数据绑定与双向数据绑定

1、单向数据绑定 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>数据绑定</title><!--引入vue--><script type"text/javascript" src"https://cdn.jsdelivr.net/npm/…...

【Flutter 开发实战】Dart 基础篇:常用运算符

在Dart中&#xff0c;运算符是编写任何程序的基本构建块之一。本文将详细介绍Dart中常用的运算符&#xff0c;以帮助初学者更好地理解和运用这些概念。 1. 算术运算符 算术运算符用于执行基本的数学运算。Dart支持常见的加、减、乘、除、整除以及取余运算。常见的算数运算符如…...

C++:ifstream通过getline读取文件会忽略最后一行空行

getline是读取文件的常用函数,虽然使用简单,但是有一个较容易被忽视的问题,就是文件最后一行空行会被忽略。 #include <iostream> #include <fstream> #include <string> using namespace std;void readWholeFileWithGetline(string fileName) {string t…...

力扣123. 买卖股票的最佳时机 III

动态规划 思路&#xff1a; 最多可以完成两笔交易&#xff0c;因此任意一天结束后&#xff0c;会处于5种状态&#xff1a; 未进行任何操作&#xff1b;只进行了一次买操作&#xff1b;进行了一次买操作和一次卖操作&#xff1b;再完成了一次交易之后&#xff0c;进行了一次买操…...

Vue3:vue-cli项目创建

一、node.js检测或安装&#xff1a; node -v node.js官方 二、vue-cli安装&#xff1a; npm install -g vue/cli # OR yarn global add vue/cli/*如果安装的时候报错&#xff0c;可以尝试一下方法 删除C:\Users**\AppData\Roaming下的npm和npm-cache文件夹 删除项目下的node…...

C# .Net学习笔记—— 异步和多线程(Task)

一、概念 Task是DotNet3.0之后所推出的一种新的使用多线程的方式&#xff0c;它是基于ThreadPool线程进行封装的。 二、使用多线程的时机 任务能够并发运行的时候&#xff0c;提升速度&#xff1b;优化体验 三、基本使用方法 private void button5_Click(object sender, Ev…...

Python从入门到网络爬虫(读写Excel详解)

前言 Python操作Excel的模块有很多&#xff0c;并且各有优劣&#xff0c;不同模块支持的操作和文件类型也有不同。最常用的Excel处理库有xlrd、xlwt、xlutils、xlwings、openpyxl、pandas&#xff0c;下面是各个模块的支持情况&#xff1a; 工具名称.xls.xlsx获取文件内容写入…...

Mysql之子查询、连接查询(内外)以及分页查询

目录 一.案例&#xff08;接上篇博客&#xff09; 09&#xff09;查询学过「张三」老师授课的同学的信息 10&#xff09;查询没有学全所有课程的同学的信息 11&#xff09;查询没学过"张三"老师讲授的任一门课程的学生姓名 12&#xff09;查询两门及其以上不及格课程…...

计算机的存储单位

在计算机中&#xff0c;只能识别二进制。 byte是1个字节&#xff0c;是8个比特位&#xff0c;所以byte可以存储的最大值是&#xff1a;01111111&#xff0c;byte是 [-128 ~ 127] 共可以标识256个不同的数字。 1字节 8bit&#xff08;8比特&#xff09;--> 1byte 8bit 类…...

设备树文件中的设备节点

一. 简介 前面几篇文章学习了 关于设备树文件的编译&#xff0c;设备树文件的调用。 本文开始学习 设备树文件的语法。具体学习设备节点与标准属性。 二. 设备树文件之设备节点与标准属性 1. 设备节点 设备树 是采用树形结构来描述板子上的设备信息的文件&#xff0c;每…...

文件管理工具.netcore资源文件管理

文件管理工具 怎么快速有效的管理我的文件包括文件夹&#xff0c;需求功能是 模糊搜索显示匹配的文件夹或文件数据 快速打开文件夹位置 在windows直接查看搜索速度太慢&#xff0c;范围宽泛&#xff0c;整理所需资源文件名和文件本机路径保存在数据库&#xff0c;可以在数据库中…...

go-carbon v2.3.4 发布,轻量级、语义化、对开发者友好的 Golang 时间处理库

carbon 是一个轻量级、语义化、对开发者友好的 golang 时间处理库&#xff0c;支持链式调用。 目前已被 awesome-go 收录&#xff0c;如果您觉得不错&#xff0c;请给个 star 吧 github.com/golang-module/carbon gitee.com/golang-module/carbon 安装使用 Golang 版本大于…...

vue3 内置组件

文章目录 前言一、过渡效果相关的组件1、Transition2、TransitionGroup 二、状态缓存组件&#xff08;KeepAlive&#xff09;三、传送组件&#xff08;Teleport &#xff09;四、异步依赖处理组件&#xff08;Suspense&#xff09; 前言 在vue3中 其提供了5个内置组件 Transiti…...

MFC如何动态创建button按钮并添加点击事件

在MFC中&#xff0c;可以使用CButton类来动态创建按钮。下面是一个示例代码&#xff0c;演示了如何动态创建按钮并添加点击事件&#xff1a; 在对话框类的头文件中声明按钮变量&#xff1a; CButton m_btnDynamic;在对话框的OnInitDialog()函数中使用Create()函数创建按钮&am…...

Qt - QML框架

文章目录 1 . 前言2 . 框架生成3 . 框架解析3.1 qml.pro解析3.2 main.cpp解析3.3 main.qml解析 4 . 总结 【极客技术传送门】 : https://blog.csdn.net/Engineer_LU/article/details/135149485 1 . 前言 什么是QML&#xff1f; QML是一种用户界面规范和编程语言。它允许开发人员…...

Python+Flask+MySQL的图书馆管理系统【附源码,运行简单】

PythonFlaskMySQL的图书馆管理系统【附源码&#xff0c;运行简单】 总览 1、《的图书馆管理系统》1.1 方案设计说明书设计目标需求分析工具列表 2、详细设计2.1 登录2.2 注册2.3 程序主页面2.4 图书新增界面2.5 图书信息修改界面2.6 普通用户界面2.7 其他功能贴图 3、下载 总览…...

Module-Federation[微前端]

Module-Federation 微前端简介我们为什么没有延续使用【乾坤】使用Module-Federation 优/缺EMP 优EMP 缺图解DEMO详解`Tips:` [文件资源](https://download.csdn.net/download/alnorthword/88699315)微前端简介 微前端是借鉴了微服务的理念,将一个庞大的应用拆分成多个独立灵活…...

Spring 动态数据源事务处理

在一般的 Spring 应用中,如果底层数据库访问采用的是 MyBatis,那么在大多数情况下,只使用一个单独的数据源,Spring 的事务管理在大多数情况下都是有效的。然而,在一些复杂的业务场景下,如需要在某一时刻访问不同的数据库,由于 Spring 对于事务管理实现的方式,可能不能达…...

WSL2-Ubuntu22.04子系统图形化界面搭建与远程桌面连接

提示&#xff1a;文中不提供WSL2子系统搭建步骤&#xff0c;假定子系统已建立好&#xff1a; 文章目录 检查WSL子系统状态图形化界面安装远程桌面连接可能遇到的相关问题xrdp状态异常远程桌面黑屏 检查WSL子系统状态 wsl -l -v如下图所示为正常 图形化界面安装 以此执行如下…...

淘宝直播要先建设个网站吗/黑马培训机构可靠吗

Prefacio 平静的生活下暗流涌动&#xff0c;明明每天浪费半天的时间&#xff0c;为什么没有急迫感。不但没有急迫感&#xff0c;也没有普通到让人以为是做梦的感觉&#xff0c;我到底该怎么办。 CatlogoPrefacioNmero0-910-1920-2930/40/50/60/70/80/90/10030以上100以下的非整…...

上海缪斯设计公司的主题文化/旧版优化大师

概述 有时候我们需要查找指定目录下的最大文件&#xff0c;通常说的指定目录包括该目录下的所有文件和子目录下的所有文件。如下是几种能查找最大文件的方法。 方法一 查找指定目录下的最大文件&#xff0c;但不包括所有子目录&#xff0c;只包括当前目录。命令格式如下&…...

广州市政府门户网站建议/如何提高搜索引擎优化

从现在开始&#xff0c;会陆续写一些ArcGIS Desktop系列软件的一些应用。源于最近买了一本书《基于GIS的数量方法与应用》&#xff0c;王法辉 著。书中介绍了很多很多GIS应用与各行各业的一些实例&#xff0c;对学GIS的人有很多的启发。我个人认为单单的GIS没什么了不起的&…...

抖音引流推广软件/seo自动工具

算法分析车辆路径规划寻路算法有很多&#xff0c;apollo路径规划模块使用的是启发式搜索算法A*寻路算法。a*算法是一种在路网上中求解最短路径的直接搜索寻路算法,原理是引入估价函数&#xff0c;加快搜索速度&#xff0c;提高了局部择优算法搜索的精度&#xff0c;成为当前较为…...

做外贸 需要做网站吗/免费做网站软件

一、tasklet使用 Tasklet的使用比较简单&#xff0c;只需要定义tasklet及其处理函数并将两者关联 例子&#xff1a; Void my_tasklet_func(unsigned long) DECLARE_TASKLET(my_tasklet.my_tasklet_func,data) 代码DECLARE_TASKLET实现了定义名称为my_tasklet的tasklet并将其与m…...

企业网站建设一般要素/seo薪资

虽然我在书法教学中一直强调基础最重要&#xff0c;笔法是根本&#xff1b;章法是最后才管的事。但是我们学书法&#xff0c;其实就是为了最后能够写出完整的作品。一幅书法作品如果只是把字整整齐齐码到纸上&#xff0c;那也算不得艺术。而书法中&#xff0c;让我们着迷&#…...