【高阶数据结构】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; //代表键值keyT2 second; //表示与key对应的信息valuepair(): 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(); //......//遍历输出mscout << endl;    cout << "test_find:";auto pos = ms.find(4);//......//从pos开始遍历输出mscout << 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. 两个数组的交集

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

单核cpu是怎么处理多线程的

首先&#xff0c;要先了解几个概念&#xff1a; 1、线程是CPU调度和分配的基本单位。 2、进程是操作系统进行资源分配&#xff08;包括cpu、内存、磁盘IO等&#xff09;的最小单位 。 3、一个进程可以包括多个线程。 4、CPU的时间片是由计算机的操作系统OS里的调度器分配的. …

NFTScan | 08.21~08.27 NFT 市场热点汇总

欢迎来到由 NFT 基础设施 NFTScan 出品的 NFT 生态热点事件每周汇总。周期&#xff1a;2023.08.21~ 2023.08.27 NFT Hot News 01/ NFT 品牌体验平台 Recur 将于 11 月 16 日彻底关闭&#xff0c;此前曾获 5000 万美元融资 8 月 21 日&#xff0c;NFT 品牌体验平台 Recur 在 X…

Oracle创建控制列表ACL(Access Control List)

Oracle创建控制列表ACL&#xff08;Access Control List&#xff09; Oracle ACL简介一、先登陆163邮箱设置开启SMTP。二、Oracle ACL控制列表处理&#xff08;一&#xff09;创建ACL&#xff08;create_acl&#xff09;&#xff08;二&#xff09;添加ACL权限&#xff08;add_…

【算法专题突破】双指针 - 盛最多水的容器(4)

目录 1. 题目解析 2. 算法原理 3. 代码编写 写在最后&#xff1a; 1. 题目解析 题目链接&#xff1a;11. 盛最多水的容器 - 力扣&#xff08;Leetcode&#xff09; 这道题目也不难理解&#xff0c; 两边的柱子的盛水量是根据短的那边的柱子决定的&#xff0c; 而盛水量…

开源项目的测试和质量保证

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

世纪互联收入增长放缓,低于华尔街预期,全年业绩指引令投资者失望

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 全年业绩指引令投资者失望 世纪互联&#xff08;VNET&#xff09;在发布了第二季度喜忧参半的财务业绩后&#xff0c;依然坚持了此前发布的2023财年业绩指引。 财报显示&#xff0c;虽然世纪互联第二季度的收入同比增长了6…

13、Vue3 大事件管理系统

一、大事件项目介绍 和 创建 1.1 Vue3 大事件管理系统 在线演示&#xff1a; https://fe-bigevent-web.itheima.net/login 接口文档: https://apifox.com/apidoc/shared-26c67aee-0233-4d23-aab7-08448fdf95ff/api-93850835 基地址&#xff1a; http://big-event-vue-api-t.i…

ardupilot开发 --- EKF篇

状态估计的算法发展 参数调试 AHRS_EKF_USE: set to “1” to use the EKF, “0” to use DCM for attitude control and inertial nav (Copter-3.2.1) or ahrs dead reckoning (Plane) for position control. In Copter-3.3 (and higher) this parameter is forced to “1” …

搭建 Gitlab

当设置和配置 GitLab 实例并执行诸如创建群组、项目、用户和上传代码等操作时&#xff0c;涉及到多个步骤&#xff0c;每个步骤都有特定的目的。让我们逐步解释每个步骤并说明其背后的原因&#xff1a; 安装必需的软件&#xff1a; yum install -y curl policycoreutils-python…

“超级AI助手:全新提升!中文NLP训练框架,快速上手,海量训练数据,ChatGLM-v2、中文Bloom、Dolly_v2_3b助您实现更智能的应用!”

“超级AI助手&#xff1a;全新提升&#xff01;中文NLP训练框架&#xff0c;快速上手&#xff0c;海量训练数据&#xff0c;ChatGLM-v2、中文Bloom、Dolly_v2_3b助您实现更智能的应用&#xff01;” 1.简介 目标&#xff1a;基于pytorch、transformers做中文领域的nlp开箱即用…

网络地址转换NAT-动态NAT的使用范围和配置-思科EI,华为数通

网络地址转换NAT-动态NAT的使用范围和配置 什么是动态NAT&#xff1f; 使用公有地址池&#xff0c;并以先到先得的原则分配这些地址。当具有私有 IP 地址的主机请求访问 Internet 时&#xff0c;动态 NAT 从地址池中选择一个未被其它主机占用的 IP 地址一对一的转化。当数据会话…

Java源码分析(二)Double

本篇是源码分析的第二篇&#xff0c;上篇我们一起分析了Integer类的源码&#xff0c;本篇一起学习下Double类的源码&#xff0c;看下其实现。 一、Double类图 首先&#xff0c;相比Integer&#xff0c;Double类的源码只有1000行代码。如下是Integer及其关联类/接口的类图&#…

ssm+vue中国咖啡文化宣传网站源码和论文

ssmvue中国咖啡文化宣传网站源码和论文078 开发工具&#xff1a;idea 数据库mysql5.7 数据库链接工具&#xff1a;navcat,小海豚等 技术&#xff1a;ssm 课题背景 随着时代的发展和人们生活理念的进一步改变&#xff0c;咖啡业已经成为了全球经济中发展最迅猛的产业之一。…

专访 Hyper Oracle:可编程的 zkOracle 打造未来世界的超算

许多 Web3 应用在实现的过程中&#xff0c;常常会遇到基础设施方面的限制&#xff0c;包括去中心化自动化、预言机、链上信息搜索等问题。绝大部分区块链的中间件网络都是依赖于节点质押来保证节点执行的诚实性&#xff0c;这样的模式会产生诸多衍生问题&#xff0c;例如安全性…

几个nlp的小任务(多选问答)

@TOC 安装库 多选问答介绍 定义参数、导入加载函数 缓存数据集 随机选择一些数据展示 进行数据预处理部分(tokenizer) 调用t

基于SSM+vue框架的个人博客网站源码和论文

基于SSMvue框架的个人博客网站源码和论文061 开发工具&#xff1a;idea 数据库mysql5.7 数据库链接工具&#xff1a;navcat,小海豚等 技术&#xff1a;ssm &#xff08;设计&#xff09;研究背景与意义 关于博客的未来&#xff1a;在创办了博客中国(blogchina)、被誉为“…

2023最新任务悬赏平台源码uniapp+Thinkphp新款悬赏任务地推拉新充场游戏试玩源码众人帮威客兼职任务帮任务发布分销机

新款悬赏任务地推拉新充场游戏试玩源码众人帮威客兼职任务帮任务发布分销机制 后端是&#xff1a;thinkphpFastAdmin 前端是&#xff1a;uniapp 1.优化首页推荐店铺模块如有则会显示此模块没有则隐藏。 2修复首页公告&#xff0c;更改首页公告逻辑。&#xff08;后台添加有公…

C# 学习笔记--个人学习使用 <1>

C# 学习笔记 Chapter 1 C# 比较软的基础部分Section 1 类与命名空间Part 1 命名空间 NameSpacePart 2 类 Class Section 2 基本元素Section 3 数据类型Part 1 什么是类型&#xff1f;Part 2 类型在 C Sharp 中的作用Part 3 C Sharp 中的数据类型 Section 4 变量、对象与内存Par…

URI和URL和URN区别

URI、URL 和 URN 是一系列从不同角度来看待资源标识和定位的概念。虽然它们有一些重叠&#xff0c;但每个概念都强调了不同的方面。 URI&#xff08;Uniform Resource Identifier&#xff09;&#xff1a;URI 是一个通用的术语&#xff0c;用于标识和定位资源。它是一个抽象的概…

多线程(二)

一.关于线程的常用操作 1.启动线程 run(): 对于run方法的覆写只是指定线程要做的任务清单&#xff0c;而不是真正的启动线程 start()&#xff1a; start()方法才是真正的在底层创建出一个线程&#xff0c;并且启动 2.中断线程 1.通过共享的标记来中断 package demo; impor…