【高阶数据结构】map和set的介绍和使用 {关联式容器;键值对;map和set;multimap和multiset;OJ练习}

map和set的介绍和使用

一、关联式容器

关联式容器和序列式容器是C++ STL中的两种不同类型的容器。

  • 关联式容器是基于键值对的容器,其中每个元素都有一个唯一的键值,可以通过键值来访问元素。关联式容器包括set、multiset、map和multimap。

  • 序列式容器是基于元素序列的容器,其中元素按照一定的顺序排列,可以通过元素的位置来访问元素。序列式容器包括vector、deque、list和array。

  • 关联式容器和序列式容器的主要区别在于它们的存储方式和访问方式。关联式容器使用二叉搜索树等数据结构来存储元素,可以快速地查找元素,但是插入和删除元素的效率较低。序列式容器使用数组或链表等数据结构来存储元素,可以快速地插入和删除元素,但是查找元素的效率较低。

在选择使用关联式容器还是序列式容器时,需要根据具体的需求来进行选择。如果需要按照键值来查找并访问元素,可以选择关联式容器;如果需要按照元素的位置来访问元素,可以选择序列式容器。

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

二、键值对

在这里插入图片描述

用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量key和value,key代表键值,value表示与key对应的信息。比如:现在要建立一个英汉互译的字典,那该字典中必然有英文单词与其对应的中文含义,而且,英文单词与其中文含义是一一对应的关系,即通过该英文单词,在词典中就可以找到与其对应的中文含义。

在C++中的键值对结构是pair,它是一个类模版。下面是SGI-STL中关于键值对的定义:

template <class T1, class T2>
struct pair
{
	typedef T1 first_type;
	typedef T2 second_type;
	T1 first; //代表键值key
	T2 second; //表示与key对应的信息value
	pair(): first(T1()), second(T2())
	{}
	pair(const T1& a, const T2& b): first(a), second(b)
	{}
};

注意:pair类在头文件<utility>中声明,<utility>又被头文件<map>包含。


三、set的介绍和使用

3.1 set的介绍

  1. set是按照一定次序存储元素的容器,底层实际就是平衡二叉搜索树(红黑树)的K模型。

  2. set中的元素不能在容器中修改(元素总是const),但是可以从容器中插入或删除它们。

  3. 在内部,set中的元素总是按照其内部比较对象(仿函数)所指示的特定严格弱排序准则进行排序。

注意:

  1. set中只放键值key,插入元素时,只需要插入key即可,不需要构造键值对。
  2. set中的元素不可以重复,因此可以使用set进行去重
  3. 使用set的迭代器遍历set中的元素,可以得到有序序列
  4. set中查找某个元素,时间复杂度为:log_2 n
  5. set中的元素不允许修改,因为修改set中的元素会破坏二叉搜索树结构。

set的模板参数列表

在这里插入图片描述

  • T: set中存放元素的类型,也就是键值key的类型。
  • Compare:比较对象(仿函数),set中元素默认按照小于来比较。
  • Alloc:set中元素空间的管理方式,默认使用STL提供的空间配置器管理。

3.2 set的使用

3.2.1 Constructor

在这里插入图片描述


3.2.2 Iterator

在这里插入图片描述

注意:set的迭代器是按照搜索二叉树的中序遍历顺序遍历set中的元素,所以当比较对象默认为Less时:set正向迭代器的遍历结果是升序序列;逆向迭代器的遍历结果是降序序列;


3.2.3 Modifiers

insert && erase

在这里插入图片描述

在这里插入图片描述


swap

在这里插入图片描述

调用set::swap完成交换后,容器中的元素是调用前 x 中的元素。所有的迭代器,引用,指针对交换后的对象仍然有效。

底层原理:set::swap是浅交换,只是将两个set中的root指针做了交换。


3.2.4 Operations

find

在这里插入图片描述

返回值:找到了返回元素的迭代器;找不到返回set::end;


count

在这里插入图片描述


lower_bound && upper_bound

在这里插入图片描述

返回值:返回容器中>=val的第一个元素的迭代器

在这里插入图片描述

返回值:返回容器中>val的第一个元素的迭代器


equal_range
在这里插入图片描述

返回值:用键值对pair返回容器中等于val的元素的迭代器范围,其中first<=valsecond>val


3.3 multiset的介绍和使用

multiset:允许存在键值相等的元素(允许键值冗余)

在这里插入图片描述

multiset和set拥有相同的成员函数,但用法略有不同:

  1. multiset::find:如果有多个键值相等的元素,返回中序遍历中的第一个。
  2. multiset::erase(val):如果有多个键值相等的元素,将所有值为val的元素全部删除。
  3. multiset::count(val):统计容器中值为val的元素个数。

测试代码:

void Test1(){
  multiset<int> ms = {1,4,2,6,3,7,4,2,4,1}; //c++11语法:初始化列表构造
  multiset<int>::iterator it = ms.begin();
  while(it != ms.end())
  {    
    cout << *it << " ";    
    ++it;    
  }    
  cout << endl;    
    
  cout << "test_erase:";    
  ms.erase(1);    
  it = ms.begin(); 
  //......
  //遍历输出ms
  cout << endl;    
    
  cout << "test_find:";
  auto pos = ms.find(4);
  //......
  //从pos开始遍历输出ms
  cout << endl;
    
  cout << "test_count:";
  cout << ms.count(4) << endl;  
}

运行结果:

在这里插入图片描述


四、map的介绍和使用

4.1 map的介绍

  1. map是按照特定次序存储<key,value>键值对的容器,底层实际就是平衡二叉搜索树(红黑树)的KV模型。

  2. 在map中,键值key通常用于排序和惟一标识元素,而值value中存储与此键值key关联的内容。键值key和值value的类型可能不同,并且在map的内部,key与value通过成员类型value_type绑定在一起,value_type是键值对pair类型。在这里插入图片描述

  3. 在内部,map中的元素总是按照键值key进行比较排序的。

map的模版参数列表

在这里插入图片描述

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

注意:在使用map时,需要包含头文件<map>。


4.2 map的使用

map和set的使用大体相同,不做过多介绍。举两个例子具体来看:在上一章节《二叉搜索树》的KV模型应用部分,有两个应用实例:用二叉搜索树的KV模型实现字典和单词计数器。现在我们用map来实现:

4.2.1 例一:Dictionary

void Dictionary(){
  map<string, string> dict;
  //map存储的元素是键值对pair,有以下几种pair的构造插入方法:
  //1.匿名对象构造法
  dict.insert(pair<string, string>("string", "字符串"));
  //2.typedef类型重命名,缩短类型名
  typedef pair<string, string> DictKV;
  //3.通过make_pair函数模版构造键值对(推荐)
  dict.insert(DictKV("peach", "桃子"));    
  dict.insert(make_pair("dictionary", "字典"));    
  dict.insert(make_pair("temporary", "短暂的"));
  dict.insert(make_pair("declaration", "声明"));    
    
  //map的迭代器遍历
  //map的迭代器底层是指向pair键值对结构的指针
  //map<string, string>::iterator it = dict.begin();                   
  auto it = dict.begin(); //map迭代器的类型过长,通过auto自动识别类型    
  while(it != dict.end())                        
  {    
    //cout << (*it).first << ":" << (*it).second << endl; //解引用后通过.访问pair的成员    
    cout << it->first << ":" << it->second << endl;//直接通过->访问pair的成员(推荐)  
    ++it;    
  } 
   
  //范围for:
  //for(pair<const string, string> &e : dict) //map存储的元素是键值对pair,注意key是const类型
  for(auto &e : dict) //临时变量e应该取引用,避免发生拷贝构造,浪费资源   
  {    
    cout << e.first << ":" << e.second << endl; 
  }
    
  string input;
  while(cin >> input)                     
  {
    auto ret = dict.find(input); //传入key值,返回对应元素(pair)的迭代器
    if(ret != dict.end()) //找不到返回map::end
    {
      cout << ret->first << ":" << ret->second << endl;
    }
    else{
      cout << "There is no such word!" << endl;
    }
  }
}

make_pair

在这里插入图片描述

在这里插入图片描述

  1. make_pair是一个函数模版,作用是利用传入的两个参数构造键值对pair并返回(传值返回)。

  2. 利用了函数模版的隐式实例化:通过传入的参数类型自动推导pair的模版参数。

  3. make_pair在头文件<utility>中声明,<utility>又被头文件<map>包含。


4.2.2 例二:WordCounter

void WordCounter(){
  map<string, int> counter;
  string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜","苹果", "香蕉", "苹果", "香蕉"};
  //方法一:上一章讲过的方法
  //for(string &e : arr)
  //{
  //  auto ret = counter.find(e);
  //  if(ret != counter.end())
  //  {
  //    ++ret->second; 
  //  } 
  //  else{
  //    counter.insert(make_pair(e,1));                                                                                          
  //  }
  //}
    
  //方法二:operator[](推荐)
  for(string &e : arr)
  {
    //如果e不在counter中,先插入pair(e,int()),再对返回value(次数)++;
    //如果e在counter中,返回value(次数)的引用,次数++;
    ++counter[e];
  }
  for(auto &e : counter)
  {
    cout << e.first << ":" << e.second << endl;
  }
}

operator[]

在这里插入图片描述

  1. map支持operator[],但与vector等连续存储容器的位置下标访问不同,map支持关键字下标访问,[]中填入key值:

  2. 如果map中有这个key,返回对应value的引用。(查找+修改value)

  3. 如果map中没有这个key,会插入一个pair(key,value()),并返回新创建的value的引用。(插入+修改value)

  4. 所谓pair(key,value())使用给定的key和value的默认构造创建的pair键值对。

  5. map::at是一个和operator[]功能相似的成员函数。当key存在时和[]有相同的行为;但当key不存在时,at不会创建新元素而是直接抛异常。

  6. operator[]的底层实现相当于:

    mapped_type& operator[] (const key_type& k)
    {
        return (*((this->insert(make_pair(k,mapped_type()))).first)).second;
    }
    //下面代码的可读性更高,更简洁。
    mapped_type& operator[] (const key_type& k)
    {
        pair<iterator, bool> ret = insert(make_pair(k,mapped_type()));
        return ret.first->second;
    }
    

insert

在这里插入图片描述

  1. 如果key已经在map中,插入失败,返回pair(key_iterator, false);
  2. 如果key不在map中,插入成果,返回pair(newkey_iterator, true);

4.3 multimap的介绍和使用

  1. multimap和map的唯一不同就是:map中的key是唯一的,而multimap中允许存在键值相等的元素(允许键值冗余)
  2. 没有重载operator[]:由于键值冗余,无法确定唯一的value。
  3. multimap中的接口可以参考map,功能都是类似的。

五、OJ练习

692. 前K个高频单词

349. 两个数组的交集

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

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

相关文章

聚焦磷酸铁锂产线革新,宏工科技一站式解决方案

兼顾了低成本与安全性两大属性&#xff0c;磷酸铁锂市场在全球范围内持续升温&#xff0c;并有望保持较高的景气度。巨大的需求空间之下&#xff0c;行业对于锂电装备企业的自动化与智能化水平、整线交付能力、产品效率与稳定性等均提出了新的要求。 以宏工科技股份有限公司&a…

MySql014——分组的GROUP BY子句排序ORDER BYSELECT子句顺序

前提&#xff1a;使用《MySql006——检索数据&#xff1a;基础select语句&#xff08;使用products表、查询单列、多列、所有列、DISTINCT去除重复行、LIMIT限制返回结果的行数、了解完全限定&#xff09;》中创建的products表 一、GROUP BY子句基础用法 SELECT vend_id, COU…

【ArcGIS Pro二次开发】(63):批量更改字段别名

在我工作中遇到的大多数图斑&#xff0c;字段名称一般是英文&#xff0c;字段别名是中文&#xff0c;使用起来是比较方便的。 但有时候也会遇到一些不一样的情况&#xff0c;不知是经过了怎样的处理&#xff0c;图斑的字段别名被修改成了和字段名称一样的英文&#xff0c;这样…

仓储23代拣货标签操作指导

服务器使用 V1.4基站已经内置服务程序&#xff0c;无需搭建服务&#xff1b;可跳至第1.4部分 服务器搭建 安装mysql5.7, 创建db_wms数据库并导入原始数据库文件 安装jdk1.8, 配置java环境变量 下载tomca8.0, 部署wms.war到tomcat, 并启动tomcat 下载资源 Windows 64bit: …

HTTP原理与实现

一、基本概念 一、基本原理* 1、全称&#xff1a; HyperText Transfer Protocol (超文本传输协议) 2、底层实现协议&#xff1a;建立在 TCP/IP 上的无状态连接。 3、基本作用&#xff1a;用于客户端与服务器之间的通信&#xff0c;规定客户端和服务器之间的通信格式。包括请…

Remmina在ubuntu22.04中无法连接Windows

Remmina在ubuntu22.04中无法连接Windows 问题 提示为&#xff1a; 无法通过TLS到RDP服务器… 分析 原因是Remmina需要使用openssl通过RDP加密与Windows计算机连接&#xff0c;而ubuntu22.04系统中OpenSSL版本为3.0&#xff0c;Openssl3 将 tls<1.2 和 sha1 的默认安全级别…

scikit-learn中OneHotEncoder用法

One-Hot编码&#xff0c;又称为一位有效编码&#xff0c;是分类变量作为二进制向量的表示。这首先要求将分类值映射到整数值&#xff0c;然后&#xff0c;每个整数值被表示为二进制向量&#xff0c;将整数索引标记为1&#xff0c;其余都标为0。 OneHotEncoder()常用参数解释 …

5年经验之谈 —— 性能测试中故障排查及解决方法!

引言&#xff1a; 在进行性能测试过程中&#xff0c;同事反馈报错率突然攀升。通过查看相关日志和服务器状态&#xff0c;发现了一些关键信息。本文将详细介绍导致报错率攀升的原因&#xff0c;并提供相应的解决方法。 1. 问题背景 在使用JMeter进行性能测试时&#xff0c;我…

go gin 自定义验证

我们上一篇已经提到了gin中binding时候可以指定json字段大小等限制&#xff0c;但是那个错误却是英文的&#xff0c;现在想搞成中文的&#xff0c;以便前端可读&#xff0c;demo如下 package mainimport ("net/http""reflect""github.com/gin-gonic/…

高忆管理:美股涨、欧股涨、中概股大爆发!这一夜,市场经历了什么

当地时间周一&#xff0c;投资者等待本周即将公布的多项重要数据的同时&#xff0c;继续消化美联储年内再加息一次的预期&#xff0c;危险偏好有所提高&#xff0c;推进美国三大股指集体上涨。到收盘&#xff0c;道指涨0.62%&#xff0c;标普500指数涨0.63%&#xff0c;纳指涨0…

【Day-22慢就是快】代码随想录-栈与队列-前K个高频元素

给定一个非空的整数数组&#xff0c;返回其中出现频率前 k 高的元素。 示例 1: 输入: nums [1,1,1,2,2,3], k 2输出: [1,2] 示例 2: 输入: nums [1], k 1输出: [1] ———————————————————————————————————————— 这道题目主要涉…

浅谈视频汇聚平台EasyCVR视频平台在城市安全综合监测预警台风天气中的重要作用

夏日已至&#xff0c;台风和暴雨等极端天气频繁出现。在城市运行过程中&#xff0c;台风所带来的暴雨可能会导致城市内涝等次生灾害&#xff0c;引发交通瘫痪、地铁停运、管网泄漏爆管、路面塌陷、防洪排涝、燃气爆炸、供热安全、管廊安全、消防火灾等安全隐患&#xff0c;影响…

深度强化学习。介绍。深度 Q 网络 (DQN) 算法

马库斯布赫霍尔茨 一. 引言 深度强化学习的起源是纯粹的强化学习&#xff0c;其中问题通常被框定为马尔可夫决策过程&#xff08;MDP&#xff09;。MDP 由一组状态 S 和操作 A 组成。状态之间的转换使用转移概率 P、奖励 R 和贴现因子 gamma 执行。概率转换P&#xff08;系统动…

解决maven仓库无法自动下载程序包的问题

在调试idea项目报错&#xff1a;未解析的依赖项:de.fhpotsdam:unfolding:jar:0.9.6 问题描述解决方法总结 问题描述 在调试idea项目时报如上所示错误&#xff0c;并尝试了网上所说的更改maven仓库为阿里云仓库等方法&#xff0c;但是maven均无法自动下载unfolding程序包。 解…

论文笔记: One Fits All:Power General Time Series Analysis by Pretrained LM

1 intro 时间序列领域预训练模型/foundation 模型的研究还不是很多 主要挑战是缺乏大量的数据来训练用于时间序列分析的基础模型——>论文利用预训练的语言模型进行通用的时间序列分析 为各种时间序列任务提供了一个统一的框架 论文还调查了为什么从语言领域预训练的Transf…

Python(Web时代)—— Django数据库整合

简介 ORM框架介绍 ORM&#xff08;Object Relation Mapping&#xff09;框架&#xff0c;可以帮助我们把类和数据表进行一个映射&#xff0c;让我们可以通过类和类对象来直接操作数据库中的数据。 优势&#xff1a;根据对接的数据库引擎翻译成对应的sql语句&#xff0c;所以…

恒运资本:两市迎普涨,创业板指涨超3%,汽车配件等板块走强

29日早盘&#xff0c;A股两市低开高走&#xff0c;沪指涨幅超1%&#xff0c;创业板指涨超3%。截至午间收盘&#xff0c;沪指涨1.39%报3141.82点&#xff0c;深成指涨2.41%&#xff0c;创业板指涨3.47%%&#xff0c;两市算计成交6265亿元。北向资金净流入超38亿元。盘面上&#…

手机云控设计思路

本系统为任务分发系统,上游发布任务或者接受其他平台系统分发的任务,对任务进行规则引擎处理后分类,由核心分发系统部分进行对存活的空闲终端进行分发任务,终端做完任务后进行反馈给任务系统. 核心要处理的点是终端存活与空闲的统计、任务平均分布下发给终端的算法,保证分布的…

基于AVR128单片机智能传送装置

一、系统方案 1、板载可变电阻&#xff08;电位器&#xff09;R29的电压作为处理器ATmega128的模数转换模块中单端ADC0的模拟信号输入&#xff08;跳线JP13短接&#xff09;。 2、调节电位器&#xff0c;将改变AD转换接口ADC0的模拟信号输入&#xff0c;由处理器完成ADC0的A/D转…

Qt:界面实时响应鼠标拖动绘制

采用双缓冲实现界面实时响应鼠标的拖动绘制。 思想如下&#xff1a;首先需要两张画布pix和tempPix&#xff0c;他们都是QPixmap实例&#xff1b;pix用来保存初始界面或上一阶段以完成的绘制&#xff1b;tempPix用来作为鼠标拖动时的实时界面绘制&#xff1b;当鼠标左键按下后拖…