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

【高阶数据结构】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. 两个数组的交集

相关文章:

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

map和set的介绍和使用 一、关联式容器 关联式容器和序列式容器是C STL中的两种不同类型的容器。 关联式容器是基于键值对的容器&#xff0c;其中每个元素都有一个唯一的键值&#xff0c;可以通过键值来访问元素。关联式容器包括set、multiset、map和multimap。 序列式容器是…...

系统架构技能之设计模式-单件模式

一、开篇 其实我本来不是打算把系统架构中的一些设计模式单独抽出来讲解的&#xff0c;因为很多的好朋友也比较关注这方面的内容&#xff0c;所以我想通过我理解及平时项目中应用到的一 些常见的设计模式,拿出来给大家做个简单讲解&#xff0c;我这里只是抛砖引玉&#xff0c…...

Redis进阶 - JVM进程缓存

原文首更地址&#xff0c;阅读效果更佳&#xff01; Redis进阶 - JVM进程缓存 | CoderMast编程桅杆https://www.codermast.com/database/redis/redis-advance-jvm-process-cache.html 传统缓存的问题 传统的缓存策略一般是请求到达 Tomcat 后&#xff0c;先查询 Redis &…...

SD-WAN带您告别高成本、单一功能和安全性差

现今&#xff0c;随着企业规模不断扩大和分散办公越来越普遍&#xff0c;企业对于网络的需求也变得越来越高。然而&#xff0c;传统的组网方式面临着很多的问题&#xff0c;比如&#xff1a;成本高、功能单一、安全性差等问题。 传统组网方式有哪些&#xff1f; 传统的组网方式…...

面试必备:揭秘ArrayList和LinkedList,区别、优缺点与使用场景

大家好&#xff0c;我是你们的小米&#xff01;今天我要跟大家聊一个在面试中经常被问到的热门话题——ArrayList和LinkedList的区别、优缺点以及它们的使用场景。作为程序员&#xff0c;掌握这些知识点不仅可以在面试中脱颖而出&#xff0c;还能帮助我们更好地在项目中选择合适…...

【局部活动轮廓】使用水平集方法实现局部活动轮廓方法研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…...

Git 同步远程新的同名分支

背景 因为远程分支的提交记录过多&#xff0c;导致本地的commit内容过大&#xff0c;会产生一些问题&#xff1a; 第一次拉取时间较长占用本地和远程的存储 原因 因为项目已有一些年头&#xff0c;若是每次文件提交比较大&#xff0c;那么占用空间就更大 解决方案 该方案…...

PingCode DevOps 团队:企业CICD流水线可能会遇到的问题及解法

CICD 流水线是指一系列自动化的构建、测试和部署步骤&#xff0c;用于将应用程序从开发到生产环境的过程。在 CICD 流水线中&#xff0c;每个步骤都是自动化的&#xff0c;并且在完成后会触发下一个步骤的执行。 CICD 的价值 CICD 流水线可以帮助团队更快地交付产品&#xff…...

【LeetCode题目详解】第九章 动态规划part01 509. 斐波那契数 70. 爬楼梯 746. 使用最小花费爬楼梯 (day38补)

本文章代码以c为例&#xff01; 一、力扣第509题&#xff1a;斐波那契数 题目&#xff1a; 斐波那契数 &#xff08;通常用 F(n) 表示&#xff09;形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始&#xff0c;后面的每一项数字都是前面两项数字的和。也就是&#xff1a…...

图像处理 信号处理板 设计原理图:367-基于zynq XC7Z100 FMC接口通用计算平台

基于zynq XC7Z100 FMC接口通用计算平台 一、板卡概述 板卡由SoC XC7Z100-2FFG900I芯片来完成卡主控及数字信号处理&#xff0c;XC7Z100内部集成了两个ARM Cortex-A9核和一个kintex 7的FPGA&#xff0c;通过PL端FPGA扩展FMC、光纤、IO等接口&#xff0c;PS端ARM扩展网络、USB、R…...

PHP中header()的七种用法

我们在实际开发中经常使用header()实现一些功能&#xff0c;这篇文章介绍关于header()的7中用法&#xff0c;需要的伙伴的开参考一下。 PHP header()的7中用法&#xff1a; 1、跳转页面 可以使用header()实现跳转页面功能。 header(Location:.$url); // $url 跳转页面的地址…...

臻图信息以数字孪生技术推动智慧小区数字化建设

伴随着智慧城市建设进程的加速发展&#xff0c;加速传统小区的管理与服务向智能化升级转型。运用智慧化的管理和服务&#xff0c;利用信息技术和物联网等技术手段&#xff0c;将传统的居住区域与智能设备相结合&#xff0c;实现楼宇、社区设施、服务管理的数字化、网络化、智能…...

15.CSS发光按钮的悬停特效

效果 源码 <!DOCTYPE html> <html> <head><title>CSS Modern Button</title><link rel="stylesheet" type="text/css" href="style.css"> </head> <body><a href="#" style=&quo…...

MyBatis —— 动态SQL和缓存

前言 在上一篇文章中荔枝梳理了一些特殊的SQL查询和一对多、多对一的映射关系&#xff0c;而在这篇文章中荔枝将会梳理有关MyBatis动态SQL和MyBatis缓存的相关知识&#xff0c;同时也稍微了解了有关MyBatis中借助MAVEN中的插件管理来实现逆向工程。希望对需要的小伙伴有帮助哈哈…...

恒流电路的三种设计方案

作为硬件研发工程师相信对恒流电路不会陌生&#xff0c;本文介绍下三种恒流电路的原理图。 三极管恒流电路 三极管恒流电路 三极管的恒流电路&#xff0c;主要是利用Q2三极管的基级导通电压为0.6~0.7V这个特性&#xff1b;当Q2三极管导通&#xff0c;Q1三极管基级电压被拉低而…...

QT基础 关于QT延迟

目录 QT提供延时 1.自定义延时 2.使用QElapsedTimer 3.使用事件循环 4.跨平台延时 QT提供延时 这里提供四种方法&#xff1a; 1、多线程程序使用QThread::sleep()或者QThread::msleep()或QThread::usleep()或QThread::wait()进行延时处理。 Sleep不会释放对象锁&#x…...

LLM - LLaMA-2 获取文本向量并计算 Cos 相似度

目录 一.引言 二.获取文本向量 1.hidden_states 与 last_hidden_states ◆ hidden_states ◆ last_hidden_states 2.LLaMA-2 获取 hidden_states ◆ model config ◆ get Embedding 三.获取向量 Cos 相似度 1.向量选择 2.Cos 相似度 3.BERT-whitening 特征白化 …...

【创建型设计模式】C#设计模式之工厂模式,以及通过反射实现动态工厂。

题目如下&#xff1a; 假设你正在为一家汽车制造公司编写软件。公司生产多种类型的汽车&#xff0c;包括轿车、SUV和卡车。每种汽车都有不同的特点和功能。请设计一个工厂模式&#xff0c;用于创建不同类型的汽车对象。该工厂模式应具有以下要求&#xff1a;工厂类名为 CarFac…...

可拖拽编辑的流程图X6

先上图 //index.html&#xff0c;有时候可能加载失败&#xff0c;那就再找一个别的cdn 或者npm下载&#xff0c;如果npm下载&#xff0c; //那么需要全局引入或者局部引入&#xff0c;代码里面写法也会不同&#xff0c;详细的可以看示例<script src"https://cdn.jsdeli…...

神经网络与卷积神经网络

全连接神经网络 概念及应用场景 全连接神经网络是一种深度学习模型&#xff0c;也被称为多层感知机&#xff08;MLP&#xff09;。它由多个神经元组成的层级结构&#xff0c;每个神经元都与前一层的所有神经元相连&#xff0c;它们之间的连接权重是可训练的。每个神经元都计算…...

Xshell远程连接Kali(默认 | 私钥)Note版

前言:xshell远程连接&#xff0c;私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...

el-switch文字内置

el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...

Java 加密常用的各种算法及其选择

在数字化时代&#xff0c;数据安全至关重要&#xff0c;Java 作为广泛应用的编程语言&#xff0c;提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景&#xff0c;有助于开发者在不同的业务需求中做出正确的选择。​ 一、对称加密算法…...

MySQL 8.0 OCP 英文题库解析(十三)

Oracle 为庆祝 MySQL 30 周年&#xff0c;截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始&#xff0c;将英文题库免费公布出来&#xff0c;并进行解析&#xff0c;帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...

ios苹果系统,js 滑动屏幕、锚定无效

现象&#xff1a;window.addEventListener监听touch无效&#xff0c;划不动屏幕&#xff0c;但是代码逻辑都有执行到。 scrollIntoView也无效。 原因&#xff1a;这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作&#xff0c;从而会影响…...

大学生职业发展与就业创业指导教学评价

这里是引用 作为软工2203/2204班的学生&#xff0c;我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要&#xff0c;而您认真负责的教学态度&#xff0c;让课程的每一部分都充满了实用价值。 尤其让我…...

C++八股 —— 单例模式

文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全&#xff08;Thread Safety&#xff09; 线程安全是指在多线程环境下&#xff0c;某个函数、类或代码片段能够被多个线程同时调用时&#xff0c;仍能保证数据的一致性和逻辑的正确性&#xf…...

USB Over IP专用硬件的5个特点

USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中&#xff0c;从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备&#xff08;如专用硬件设备&#xff09;&#xff0c;从而消除了直接物理连接的需要。USB over IP的…...

Xen Server服务器释放磁盘空间

disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...

Caliper 负载(Workload)详细解析

Caliper 负载(Workload)详细解析 负载(Workload)是 Caliper 性能测试的核心部分,它定义了测试期间要执行的具体合约调用行为和交易模式。下面我将全面深入地讲解负载的各个方面。 一、负载模块基本结构 一个典型的负载模块(如 workload.js)包含以下基本结构: use strict;/…...