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

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

介绍

  1. set是按照一定次序存储元素的容器。
  2. 在set中,元素的value也标识它,并且每个value必须是唯一的。set中的元素不能在容器中修改(元素总是const,因为底层是平衡二叉树,如果修改可能会破坏平衡二叉树的性质)。
  3. 在内部,set中的元素总是按照其内部比较对象(类型比较)所指示的特定严格弱排序准则进行排序。
  4. set容器通过key访问单个元素的速度通常比unordered_set容器慢,但它们允许根据顺序对子集进行直接迭代。
  5. set在底层使用平衡二叉树(红黑树)实现的。
  6. 与map/multimap不同,map/multimap中存储的是真正的键值对<key,value>,set中只放value,但在底层实际存放的是由<value,value>构成的键值对。
  7. set中插入元素时,只需要插入value即可,不需要构造键值对。
  8. set中的元素不可以重复(因此可以使用set进行去重,不可以重复的原因也是底层是平衡二叉树)。
  9. 使用set中的元素默认按照小于来比较。
  10. set中查找某个元素,时间复杂度为:log2 n
  11. 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

介绍

  1. map是关联式容器,它按照特定的次序(按照key来比较)存储由键值key和值value组合而成的元素。
  2. 在map中,键值key通常用于排序和唯一的标识元素,而值value中存储与此键值key关联的内容。键值key和值value的类型可能不同,并且在map的内部,key和value通过成员类型value_type绑定在一起,并为其取别名为pair:typedef pair value_type;
  3. 在内部,map中的元素总是按照键值key进行比较排序的。
  4. map中通过键值访问单个元素的速度通常比unordered_map容器慢,但map允许根据顺序对元素进行直接迭代(即对map中的元素进行迭代时,可以得到一个有序的序列)。
  5. map支持下标访问符,即在[]中放入key,就可以找到与key对应的value。
  6. 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

介绍

  1. multiset是按照特定顺序存储元素的容器,其中元素是可以重复的。
  2. 在multiset中,元素的value也会识别它(因为multiset中本身存储的就是<value, value>组成的键值对,因此value本身就是key,key就是value,类型为T). multiset元素的值不能在容器中进行修改(因为元素总是const的),但可以从容器中插入或删除。
  3. 在内部,multiset中的元素总是按照其内部比较规则(类型比较)所指示的特定严格弱排序准则进行排序。
  4. multiset底层结构是一个平衡二叉树(红黑树)。
  5. 与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个高频单词

题目地址:

力扣icon-default.png?t=N2N8https://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个高频单词 关联式容器 概念 我们之前接触过的一些容器&#xff0c;比如&#xff1a;vector、list、deque、forwa…...

Qlib使用

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

TL-WDR7660 httpProcDataSrv任意代码执行漏洞复现分析

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

基于DDS的SOA测试方案实现

随着以太网技术在车载网络中的应用&#xff0c;各种基于以太网的中间件也相继被应用在车内&#xff0c;如果对车载网络有过相关了解的小伙伴&#xff0c;对于作为中间件之一的DDS&#xff08;数据分发服务Data Distribution Service&#xff09;可能并不陌生&#xff1b;若没有…...

LibTorch中Windows系统环境配置及CUDA不可用问题解决

前言&#xff1a;本文对在Windows系统上进行LibTorch开发环境配置及相关问题解决做一个较为详细的记录&#xff0c;以便后续查询使用。 使用环境版本&#xff1a; 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&#xff0c;后两个属于lock) 3.管道输入、输出流 (示例代码&#xff1a;PipeInOut.java)&#xff08;目前几乎没人使用&#xff09; 管道输入/输…...

Linux中最基本的命令ls的用法有哪些?

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

第 100002(十万零二)个素数是多少?

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

Lua迭代器

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

同步与互斥之信号量

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

如何当个优秀的文档工程师?从 TC China 看技术文档工程师的自我修养

本文系 NebulaGraph Community Academic 技术文档工程师 Abby 的参会观感&#xff0c;讲述了她在中国技术传播大会分享的收获以及感悟。 据说&#xff0c;技术内容领域、传播领域的专家和决策者们会在中国技术传播大会「tcworld China 2022」大会上分享心得。作为一名技术文档工…...

如何学习k8s

学习Kubernetes可以遵循以下步骤&#xff1a; 了解Kubernetes的基本概念和架构。学习Kubernetes前&#xff0c;需要了解它的基本概念和组成部分&#xff0c;包括Pod、Service、ReplicaSet、Deployment、Namespace等等&#xff0c;同时也需要了解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 现状 我记得去年脉脉的论调还都是 客户端已死&#xff0c;前后端还都是一片祥和&#xff0c;有秀工资的&#xff0c;有咨询客户端转前端的&#xff0c;怎么最近打开脉脉一看&#xff0c;风向变了&#xff1f; 随便刷几下&#xff0c;出来的信息…...

大家好,我是火旺技术

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

【Java并发编程系列】全方位理解多线程几乎包含线程的所有操作哦

文章目录一、概述及目录二、实现多线程的方式2.1 继承Tread类&#xff0c;重写run方法。start方法2.2 实现Runnable方法&#xff0c;并实现run接口方法2.3 实现Callable接口重写call方法&#xff0c;Feature.get()获取返回值三、线程的执行流程3.1 执行流程3.2 start方法和 run…...

天宝S6测量机器人/天宝S6全站仪参数/教程/Trimble 天宝全站仪

TRIMBLE DR PLUS技术 Trimble DR Plus™距离测量技术实现更大范围的直接反射测量&#xff0c;不使用棱镜也能进行长距离测量。难以抵达或不安全的测 量目标&#xff0c;对Trimble S6来说不再是问题。Trimble DR Plus结合 了MagDrive™磁驱伺服技术&#xff0c;使测量的快捷和…...

c++基础知识汇总

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

重磅!基于GPT-4的全新智能编程助手 GitHub Copilot X 来了!

GitHub Copilot相信大家一定不陌生了&#xff0c;强大的智能代码补全功能一度让媒体直呼程序员要被替代。随着OpenAI推出全新的GPT-4&#xff0c;GitHub Copilot也在3月22日&#xff0c;推出了全新一代产品&#xff1a;GitHub Copilot X 。最新的GitHub Copilot X 不仅可以自动…...

第04章_运算符

第04章_运算符 &#x1f3e0;个人主页&#xff1a;shark-Gao &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是shark-Gao&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f389;目前状况&#xff1a;23届毕业生&#xff0c;目前在某公…...

Docker 离线安装指南

参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性&#xff0c;不同版本的Docker对内核版本有不同要求。例如&#xff0c;Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本&#xff0c;Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...

centos 7 部署awstats 网站访问检测

一、基础环境准备&#xff08;两种安装方式都要做&#xff09; bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats&#xff0…...

如何在网页里填写 PDF 表格?

有时候&#xff0c;你可能希望用户能在你的网站上填写 PDF 表单。然而&#xff0c;这件事并不简单&#xff0c;因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件&#xff0c;但原生并不支持编辑或填写它们。更糟的是&#xff0c;如果你想收集表单数据&#xff…...

CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝

目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为&#xff1a;一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...

【Linux】自动化构建-Make/Makefile

前言 上文我们讲到了Linux中的编译器gcc/g 【Linux】编译器gcc/g及其库的详细介绍-CSDN博客 本来我们将一个对于编译来说很重要的工具&#xff1a;make/makfile 1.背景 在一个工程中源文件不计其数&#xff0c;其按类型、功能、模块分别放在若干个目录中&#xff0c;mak…...

Elastic 获得 AWS 教育 ISV 合作伙伴资质,进一步增强教育解决方案产品组合

作者&#xff1a;来自 Elastic Udayasimha Theepireddy (Uday), Brian Bergholm, Marianna Jonsdottir 通过搜索 AI 和云创新推动教育领域的数字化转型。 我们非常高兴地宣布&#xff0c;Elastic 已获得 AWS 教育 ISV 合作伙伴资质。这一重要认证表明&#xff0c;Elastic 作为 …...

【大厂机试题解法笔记】矩阵匹配

题目 从一个 N * M&#xff08;N ≤ M&#xff09;的矩阵中选出 N 个数&#xff0c;任意两个数字不能在同一行或同一列&#xff0c;求选出来的 N 个数中第 K 大的数字的最小值是多少。 输入描述 输入矩阵要求&#xff1a;1 ≤ K ≤ N ≤ M ≤ 150 输入格式 N M K N*M矩阵 输…...

虚拟机网络不通的问题(这里以win10的问题为主,模式NAT)

当我们网关配置好了&#xff0c;DNS也配置好了&#xff0c;最后在虚拟机里还是无法访问百度的网址。 第一种情况&#xff1a; 我们先考虑一下&#xff0c;网关的IP是否和虚拟机编辑器里的IP一样不&#xff0c;如果不一样需要更改一下&#xff0c;因为我们访问百度需要从物理机…...

使用python进行图像处理—图像变换(6)

图像变换是指改变图像的几何形状或空间位置的操作。常见的几何变换包括平移、旋转、缩放、剪切&#xff08;shear&#xff09;以及更复杂的仿射变换和透视变换。这些变换在图像配准、图像校正、创建特效等场景中非常有用。 6.1仿射变换(Affine Transformation) 仿射变换是一种…...

Linux【5】-----编译和烧写Linux系统镜像(RK3568)

参考&#xff1a;讯为 1、文件系统 不同的文件系统组成了&#xff1a;debian、ubuntu、buildroot、qt等系统 每个文件系统的uboot和kernel是一样的 2、源码目录介绍 目录 3、正式编译 编译脚本build.sh 帮助内容如下&#xff1a; Available options: uboot …...