C++—— set、map、multiset、multimap
目录
关联式容器
概念
键值对
树形关联式容器
set
介绍
定义方式
使用
map
介绍
使用
multiset
介绍
使用
multimap
介绍
使用
相关的OJ题
前K个高频单词
关联式容器
概念
我们之前接触过的一些容器,比如:vector、list、deque、forward_list(C++11)等,这些容器统称为序列式容器,因为其底层为线性序列的数据结构,里面存储的是元素本身。
关联式容器也是用来存储数据的,与序列式容器不同的是,其里面存储的是<key, value>结构的键值对,在数据检索时比序列式容器效率更高。
键值对
键值对是关联式容器特殊的结构。
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)
{}
};
树形关联式容器
map、set、multimap、multiset。这些都是树形关联式容器,因为他们的底层都是平衡搜索树(红黑树),容器中的元素都是有序的。
set
介绍
- set是按照一定次序存储元素的容器。
- 在set中,元素的value也标识它,并且每个value必须是唯一的。set中的元素不能在容器中修改(元素总是const,因为底层是平衡二叉树,如果修改可能会破坏平衡二叉树的性质)。
- 在内部,set中的元素总是按照其内部比较对象(类型比较)所指示的特定严格弱排序准则进行排序。
- set容器通过key访问单个元素的速度通常比unordered_set容器慢,但它们允许根据顺序对子集进行直接迭代。
- set在底层使用平衡二叉树(红黑树)实现的。
- 与map/multimap不同,map/multimap中存储的是真正的键值对<key,value>,set中只放value,但在底层实际存放的是由<value,value>构成的键值对。
- set中插入元素时,只需要插入value即可,不需要构造键值对。
- set中的元素不可以重复(因此可以使用set进行去重,不可以重复的原因也是底层是平衡二叉树)。
- 使用set中的元素默认按照小于来比较。
- set中查找某个元素,时间复杂度为:log2 n
- set中的元素不允许修改(因为底层是平衡二叉树,如果修改的话很可能会破坏平衡二叉树的结构)。
注意:平衡二叉树(AVL)是一种特殊的搜索二叉树(BST);
定义方式
//构造空容器
set<int> s1;//拷贝构造set容器
set<int> s2(s1);//使用迭代器拷贝某一段内容
string str("abcdef");
set<char> s3(str.begin(),str.end());//比较方式指定为大于
set<int,greater<int>> s4;
使用
Compare:比较容器,set默认按照小于来比较,如果要对自定义类型进行比较的时候可以传入自定义的比较容器。
详细见代码:
void test_set1()
{set<int> s;//插入s.insert(3);s.insert(2);s.insert(1);s.insert(1);s.insert(6);s.insert(7);s.insert(4);//利用迭代器去遍历set//set<int>::iterator it = s.begin();auto it = s.begin();while (it != s.end()){cout << *it << " ";it++;}cout << endl;//利用范围for去遍历for (auto e : s){cout << e << " ";}cout << endl;//查找->找到就返回该元素的迭代器 否则返回end//两种find的查找方式是不一样的//O(logN) 这个是根据树的特殊结构来查找的auto pos = s.find(3);//O(N) 暴力查找//auto pos = find(s.begin(), s.end(), 3);if (pos != s.end()){s.erase(pos);}//删除 //有就删没有就不操作//s.erase(4)像这种是有返回值的//删除成功就返回1删除失败返回0cout << s.erase(4) << endl;cout << s.erase(100) << endl;for (auto e : s){cout << e << " ";}cout << endl;//count 返回该值在set里面的个数//其实count对set意义不大//但是对multiset意义更大//cout << s.count(3) << endl;}
注意:这里只列举一些常用的set的操作。
map
介绍
- map是关联式容器,它按照特定的次序(按照key来比较)存储由键值key和值value组合而成的元素。
- 在map中,键值key通常用于排序和唯一的标识元素,而值value中存储与此键值key关联的内容。键值key和值value的类型可能不同,并且在map的内部,key和value通过成员类型value_type绑定在一起,并为其取别名为pair:typedef pair value_type;
- 在内部,map中的元素总是按照键值key进行比较排序的。
- map中通过键值访问单个元素的速度通常比unordered_map容器慢,但map允许根据顺序对元素进行直接迭代(即对map中的元素进行迭代时,可以得到一个有序的序列)。
- map支持下标访问符,即在[]中放入key,就可以找到与key对应的value。
- map通常被实现为平衡二叉搜索树(红黑树)。
使用
Compare: 比较器的类型,map中的元素是按照key来比较的,缺省情况下按照小于来比较,一般情况下(内置类型元素)该参数不需要传递,如果无法比较时(自定义类型),需要用户自己显式传递比较规则(一般情况下按照函数指针或者仿函数来传递)。
int main()
{//定义一个空容器map<string, string> dict;//插入key和valuedict.insert(pair<string, string>("排序", "sort"));dict.insert(pair<string, string>("左边", "left"));dict.insert(pair<string, string>("右边", "right"));//operator[]dict["迭代器"] = "iterator";//插入+修改dict["insert"];//插入dict["insert"] = "插入";//修改cout << dict["insert"] << endl;//查找,如果不在就是插入//插入失败因为已经有key对应的值了//dict.insert(pair<string, string>("右边", "xxx"));//make_pair是一个函数模板 可以根据你传入的值来推断具体的类型dict.insert(make_pair("字符串", "string"));//map<string, string>::iterator it = dict.begin();auto it = dict.begin();while (it != dict.end()){//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;}//可以用来统计次数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));//第一次遇见这个水果直接给对应的key的value值插入1}else{it->second++;}}//用for循环进行遍历for (const auto& kv : countMap){cout << kv.first << ": " << kv.second << endl;}return 0;
}
注意:map是支持[]操作符的。
operator[]的原理是:
用<key, T()>构造一个键值对,然后调用insert()函数将该键值对插入到map中如果key已经存在,插入失败,insert函数返回该key所在位置的迭代器如果key不存在,插入成功,insert函数返回新插入元素所在位置的迭代器operator[]函数最后将insert返回值键值对中的value返回。
multiset
介绍
- multiset是按照特定顺序存储元素的容器,其中元素是可以重复的。
- 在multiset中,元素的value也会识别它(因为multiset中本身存储的就是<value, value>组成的键值对,因此value本身就是key,key就是value,类型为T). multiset元素的值不能在容器中进行修改(因为元素总是const的),但可以从容器中插入或删除。
- 在内部,multiset中的元素总是按照其内部比较规则(类型比较)所指示的特定严格弱排序准则进行排序。
- multiset底层结构是一个平衡二叉树(红黑树)。
- 与set的区别是,multiset中的元素是可以重复的,set中value是唯一的。
使用
void test_set2()
{multiset<int> s;//插入 可以插入重复的值s.insert(2);s.insert(1);s.insert(1);s.insert(3);s.insert(3);s.insert(3);s.insert(3);s.insert(3);s.insert(3);s.insert(6);s.insert(7);s.insert(1);//set<int>::iterator it = s.begin();auto it = s.begin();while (it != s.end()){cout << *it << " ";it++;}cout << endl;for (auto e : s){cout << e << " ";}cout << endl;//注意://用来验证,如果有多个相同的值的时候//find找到是中序遍历的第一个auto pos = s.find(3);while (pos != s.end()){cout << *pos << " ";pos++;}//两种find的查找方式是不一样的//O(logN)//auto pos = s.find(3);//O(N)/*auto pos = find(s.begin(), s.end(), 3);if (pos != s.end()){s.erase(pos);}*///有就删没有就不操作//s.erase(4)像这种是有返回值的//删除成功就返回1删除失败返回0/*cout << s.erase(4) << endl;cout << s.erase(100) << endl;for (auto e : s){cout << e << " ";}cout << endl;*///count 返回该值在set里面的个数//其实count对set意义不大//但是对multiset意义更大cout << s.count(3) << endl;cout << s.count(1) << endl;
}
注意:multiset的find与set有所不同,由于multiset中允许键值冗余,所以multiset如果查找成功的话返回的是中序遍历该元素所出现的第一次的迭代器。
set中的count没什么意义,但是在multiset中count非常有意义,它能很好的计算出该元素在multiset容器中的具体数量。
multimap
介绍
multimap与set和multiset的区别非常相像,在这里不多介绍。
multimap不支持[],因为multimap允许键值冗余,[]不能确切的知道我们要访问的是哪个值。
multimap中的key是可以重复的。
使用
int main()
{multimap<string, string> dict;dict.insert(make_pair<string, string>("left", "左边"));dict.insert(make_pair<string, string>("left", "左边"));dict.insert(make_pair<string, string>("right", "右边"));dict.insert(make_pair("string", "字符串"));for (const auto& kv : dict){cout << kv.first << ":" << kv.second << endl;}
}
相关的OJ题
前K个高频单词
题目地址:
力扣https://leetcode.cn/problems/top-k-frequent-words/description/
我们这里使用multimap非常契合,我们的思路就是,首先使用multimap特殊的性质(允许键值冗余,并且有两个键值)。两个键值,一个存放单词,一个存放次数。
记录完毕数据之后使用次数进行排序,如果有相同的就设置特殊的比较容器具进行字典序排序。
最后输出前十个。
class Solution {
public:vector<string> topKFrequent(vector<string>& words, int k){//为stable_sort来创建比较容器struct Compare{bool operator()(const pair<int,string>&l,const pair<int,string>& r){return l.first>r.first;}};map<string,int> mapCount;//巧妙的使用了[] //不仅将words中的单词给插入进map并且还统计了次数for(auto& kv: words){mapCount[kv]++;//访问key对应的value给value进行++}vector<pair<int,string>> v;//注意这里value与key换了位置为了保证排序的时候直接使用第一个键值进行排序for(auto& kv : mapCount){v.push_back(make_pair(kv.second,kv.first));}//切记不要使用sort 因为sort底层为快排(不稳定)//然而stable_sort底层为归并(稳定)stable_sort(v.begin(),v.end(),Compare());vector<string> ret;for(size_t i=0;i<k;i++){ret.push_back(v[i].second);}return ret;}
};
相关文章:

C++—— set、map、multiset、multimap
目录 关联式容器 概念 键值对 树形关联式容器 set 介绍 定义方式 使用 map 介绍 使用 multiset 介绍 使用 multimap 介绍 使用 相关的OJ题 前K个高频单词 关联式容器 概念 我们之前接触过的一些容器,比如:vector、list、deque、forwa…...

Qlib使用
Qlib https://github.com/microsoft/qlib 将csv文件转化为Qlib的数据格式:https://qlib.readthedocs.io/en/latest/component/data.html#converting-csv-format-into-qlib-format 注意每支股票都要保存成单独一个文档,且文档名字与股票代号一致。 其中f…...

TL-WDR7660 httpProcDataSrv任意代码执行漏洞复现分析
01 漏洞简述 2023年1月31日,CNVD公开了一个由国内安全研究员提交的TL-WDR7660 httpProcDataSrv任意代码执行漏洞,编号为CNVD-2023-05404,同时公开了漏洞利用详情,poc代码链接为https://github.com/fishykz/TP-POC。从poc代码详情…...

基于DDS的SOA测试方案实现
随着以太网技术在车载网络中的应用,各种基于以太网的中间件也相继被应用在车内,如果对车载网络有过相关了解的小伙伴,对于作为中间件之一的DDS(数据分发服务Data Distribution Service)可能并不陌生;若没有…...

LibTorch中Windows系统环境配置及CUDA不可用问题解决
前言:本文对在Windows系统上进行LibTorch开发环境配置及相关问题解决做一个较为详细的记录,以便后续查询使用。 使用环境版本: Windows 11 Visual Studio 2022 CUDA 12.0 LibTorch 1.13.1_cu11.7 目录一、LibTorch简介二、LibTorch下载安装三…...

Java并发编程实战二
线程间的通讯方式 1.volitate(缓存一致性协议),synchronize,lock(都保证可见性) 2.wait.notify,await(),signal(前两个是Object,后两个属于lock) 3.管道输入、输出流 (示例代码:PipeInOut.java)(目前几乎没人使用) 管道输入/输…...

Linux中最基本的命令ls的用法有哪些?
Linux是一种流行的操作系统,被广泛应用于服务器和个人电脑。Linux命令行界面是使用Linux操作系统的关键。其中一个最基本的命令是"ls"命令,该命令用于列出指定目录中的所有文件和子目录。在这篇文章中,我们将探讨ls命令及其各种用途…...

第 100002(十万零二)个素数是多少?
题目描述 素数就是不能再进行等分的整数。比如7,11。而 9 不是素数,因为它可以平分为 3 等份。一般认为最小的素数是2,接着是 3,5,... 请问,第 100002(十万零二)个素数是多少? 请注意࿱…...

Lua迭代器
Lua迭代器 迭代器(iterator)是一种对象,它能够用来遍历标准模板库容器中的部分或全部元素,每个迭代器对象代表容器中的确定的地址。 在 Lua 中迭代器是一种支持指针类型的结构,它可以遍历集合的每一个元素。 泛型 f…...

同步与互斥之信号量
目录 1、信号量用于线程的互斥 验证 2、信号量用于线程的同步 验证 3、无名信号量用于进程间互斥 代码一 代码二 验证 4、有名信号量 用于进程间同步和互斥 验证 信号量广泛用于进程或线程间的同步和互斥,信号量本质上是一个非负的整数计数器,它…...

如何当个优秀的文档工程师?从 TC China 看技术文档工程师的自我修养
本文系 NebulaGraph Community Academic 技术文档工程师 Abby 的参会观感,讲述了她在中国技术传播大会分享的收获以及感悟。 据说,技术内容领域、传播领域的专家和决策者们会在中国技术传播大会「tcworld China 2022」大会上分享心得。作为一名技术文档工…...

如何学习k8s
学习Kubernetes可以遵循以下步骤: 了解Kubernetes的基本概念和架构。学习Kubernetes前,需要了解它的基本概念和组成部分,包括Pod、Service、ReplicaSet、Deployment、Namespace等等,同时也需要了解Kubernetes的整体架构和工作原理…...

【SSM】MyBatis(十.动态sql)
文章目录1.if2.where3.trim4.set5. choose when otherwise6.foreach6.1 批量删除6.2 批量增加7.sql1.if <select id"selectByMultiCondition" resultType"Car">select * from t_car where 1 1<if test"brand ! null and brand ! ">…...

最近很多人都在说 “前端已死”,讲讲我的看法
转自 : 掘金 作者 : Ethan_Zhou 现状 我记得去年脉脉的论调还都是 客户端已死,前后端还都是一片祥和,有秀工资的,有咨询客户端转前端的,怎么最近打开脉脉一看,风向变了? 随便刷几下,出来的信息…...

大家好,我是火旺技术
大家好,我是火旺技术 在Internet高速发展的今天,我们生活的各个领域都涉及到计算机的应用。这其中,家乡特色推荐的网络应用已经成为外国家乡推荐系统的一种很普遍的方式。不过,在国内,管理网站可能还处于起步阶段。 …...

【Java并发编程系列】全方位理解多线程几乎包含线程的所有操作哦
文章目录一、概述及目录二、实现多线程的方式2.1 继承Tread类,重写run方法。start方法2.2 实现Runnable方法,并实现run接口方法2.3 实现Callable接口重写call方法,Feature.get()获取返回值三、线程的执行流程3.1 执行流程3.2 start方法和 run…...

天宝S6测量机器人/天宝S6全站仪参数/教程/Trimble 天宝全站仪
TRIMBLE DR PLUS技术 Trimble DR Plus™距离测量技术实现更大范围的直接反射测量,不使用棱镜也能进行长距离测量。难以抵达或不安全的测 量目标,对Trimble S6来说不再是问题。Trimble DR Plus结合 了MagDrive™磁驱伺服技术,使测量的快捷和…...

c++基础知识汇总
目录 1、基础 1.2 注释 1.3 变量 1.4 常量 1.5 关键字 1.6 标识符命名规则 2 数据类型 2.1 整型 2.2 sizeof关键字 2.3 实型(浮点型) 2.4 字符型 2.5 转义字符 2.6 字符串型 2.7 布尔类型 bool 2.8 数据的输入 1、基础 1.2 注释 作用&a…...

重磅!基于GPT-4的全新智能编程助手 GitHub Copilot X 来了!
GitHub Copilot相信大家一定不陌生了,强大的智能代码补全功能一度让媒体直呼程序员要被替代。随着OpenAI推出全新的GPT-4,GitHub Copilot也在3月22日,推出了全新一代产品:GitHub Copilot X 。最新的GitHub Copilot X 不仅可以自动…...

第04章_运算符
第04章_运算符 🏠个人主页:shark-Gao 🧑个人简介:大家好,我是shark-Gao,一个想要与大家共同进步的男人😉😉 🎉目前状况:23届毕业生,目前在某公…...

Excel 文件比较工具:xlCompare 11.0 Crack
(Excel 文件比较工具)xlCompare 11.0 下载并安装最新版本的 xlCompare。下载是一个功能齐全的版本。 筛选匹配的行 筛选不同的行 仅显示两个 Excel 文件中存在的行,并排除新(已删除)行 隐藏在另一张工作表上具有相应行…...

802.1x认证原理
802.1x认证原理802.1X认证简介802.1X认证协议802.1X认证流程802.1X认证简介 定义:802.1x协议是一种基于端口的网络接入控制协议。基于端口的网络接入控制,是指在局域网接入设备的端口这一级验证用户身份,并且控制其访问权限。优点࿱…...

GPIO的八种模式分析
GPIO是general purpose input output,即通用输入输出端口,作用是负责外部器件的信息和控制外部器件工作。 GPIO有如下几个特点:1.不同型号的IO口数量不同;2,反转快速,每次翻转最快只需要两个时钟周期,以ST…...

携职教育:财会人常用必备,203个EXCEL快捷键汇总
会用快捷键的人早下班! 作为财务人员如果你想要提高工作效率,不掌握一些Excel快捷键怎么行? 老板看见了,也会赞一声,“看,这就是专业。” 立马给你加薪(划掉),工作效率这…...

【美赛】2023年ICM问题Z:奥运会的未来(思路、代码)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...

CSS基础入门
CSS基础之语法 介绍 CSS(层叠样式表)是一门用来设计网页样式的语言,如网页的布局、字体、颜色搭配、视觉特效。作为WEB开发的基础技术之一,掌握CSS的语法和API对于我们构建丰富的网页是必须的。 基础语法 <style>div …...

可重入锁、读写锁、邮戳锁 详解
文章目录1、可重入锁(递归锁)2、读写锁2.1、读写分离2.2、从写锁到读锁,ReentrantReadWriteLock可以降级2.3、写锁和读锁是互斥的3、邮戳锁StampedLock3.1、是什么3.2、锁饥饿3.3、如何缓解锁饥饿问题呢3.3.1、使用“公平”策略3.3.2、Stampe…...

HBase客户端、服务器端、列簇设计、HDFS相关优化,HBase写性能优化切入点,写异常问题检查点
HBase客户端、服务器端、列簇设计、HDFS相关优化,HBase写性能优化切入点,写异常问题检查点HBase读优化1.1 HBase客户端优化1) scan缓存是否设置合理?2) get请求是否可以使用批量请求?3) 请求是否可以显示指定列簇或者列࿱…...

DINO-DETR在COCO缩减数据集上实验结果分析
博主在进行DINO-DETR模型实验时,使用缩减后的COCO数据集进行训练,发现其mAP值只能达到0.27作用,故而修改了下pycocotool的代码,令其输出每个类别的AP值,来看看是由于什么原因导致这个问题。 之所以这样是因为博主认为各…...

语聊房app源码及架构设计
语音社交产品技术架构设计 语音社交产品的技术架构设计是产品开发中非常重要的一环。在设计时需要考虑产品的功能、性能、可靠性等多个方面,同时也需要与产品策划与设计相协调。以下是语音社交产品技术架构设计的主要内容。 架构设计原则 在设计语音社交产品的技…...