set类和map类介绍和简单使用

news2024/11/14 20:36:54

目录

set类介绍与简单使用

set类

multiset类

map类介绍与简单使用

map类

multimap类


set类介绍与简单使用

set类是一种关联式容器,在数据检索时比序列式容器效率更高。本质是一个常规的二叉搜索树,但是为了防止出现单支树导致效率下降进行了相关优化

set类也满足二叉搜索树的特点:

  1. 元素不重复:因此可以用来去重

  2. 默认中序遍历是升序

  3. 比较的平均次数为log_{2}{N}

  4. set中的元素不可以修改

  5. set中的底层使用二叉搜索树(红黑树)来实现

  6. 默认按照key升序排序

set类

使用set类需要包含头文件<set>

set官方文档

简单使用实例:

 #define _CRT_SECURE_NO_WARNINGS 1
 ​
 #include <iostream>
 #include <set>
 using namespace std;
 ​
 int main()
 {
     set<int> s;
     // 使用数组构造set,去重+排序
     int array[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0, 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };
     for (auto e : array)
     {
         // 插入数据
         s.insert(e);
     }
 ​
     // 使用正向迭代器遍历set
     set<int>::iterator it = s.begin();
     while (it != s.end())
     {
         cout << *it << " ";
         ++it;
     }
     cout << endl;
     // 使用反向迭代器遍历set
     set<int>::reverse_iterator rit = s.rbegin();
     while (rit != s.rend())
     {
         cout << *rit << " ";
         ++rit;
     }
 ​
     cout << endl;
 ​
     // 计数
     // set会去重,所以每一种数字只会出现1次
     cout << s.count(3) << endl;
 ​
     // 查找+删除
     s.erase(s.find(3));
     // 范围for遍历
     for (auto e : s)
     {
         cout << e << " ";
     }
     return 0;
 }

需要注意的两个函数lower_bound()upper_bound(),这两个函数放在一起的作用是获取到当前中序遍历的[lower_bound, upper_bound]区间

#define _CRT_SECURE_NO_WARNINGS 1
 ​
 #include <iostream>
 #include <set>
 using namespace std;
 ​
 int main()
 {
     set<int> s;
     // 使用数组构造set,去重+排序
     int array[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0, 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };
     for (auto e : array)
     {
         // 插入数据
         s.insert(e);
     }
     
     // lower_bound与upper_bound
     set<int>::iterator it = s.lower_bound(3);
     while (it != s.upper_bound(8))
     {
         cout << *it << " ";
         ++it;
     }
     return 0;
 }
 输出结果:
 3 4 5 6 7 8

首先解释lower_bound(3)的意思,在这个函数中,lower_bound()会取到第一个大于或者等于3的数值,返回其位置的迭代器,所以lower_bound(3)返回的是3所在位置的迭代器,接着upper_bound(8),对于upper_bound(8)会返回除8以外的比8大的数值位置的迭代器,也就是第一个大于8的数值位置的迭代器,所以上面的程序结果最后会输出8是因为取出了[3, 8]中的所有位于set容器中的值

multiset类

multiset类与set类不同的是,multiset类允许数据出现重复

multiset类官方文档

简单使用实例:

 #define _CRT_SECURE_NO_WARNINGS 1
 ​
 #include <iostream>
 #include <set>
 using namespace std;
 ​
 int main()
 {
     // 使用数组构造multiset,排序
     int array1[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0, 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };
     multiset<int> ms;
     for (auto num : array1)
     {
         ms.insert(num);
     }
 ​
     // 范围for遍历
     for (auto num : ms)
     {
         cout << num << " ";
     }
     cout << endl;
 ​
     // 统计3的次数
     cout << ms.count(3) << endl;
 ​
     // lower_bound和upper_bound
     // 在multiset中会打印[第一个4, 最后一个4]中的所有4
     multiset<int>::iterator it = ms.lower_bound(4); 
     while (it != ms.upper_bound(4))
     {
         cout << *it << " ";
         ++it;
     }
     return 0;
 }

需要注意erase()函数在multiset中的两个用法有些许不同:

#define _CRT_SECURE_NO_WARNINGS 1
 ​
 #include <iostream>
 #include <set>
 using namespace std;
 ​
 int main()
 {
     int array2[] = { 1, 3, 5, 3, 3, 2, 4, 6, 8, 0, 1, 3, 3, 7, 9, 2, 4, 6, 3, 0 };
     multiset<int> ms1;
     for (auto num : array2)
     {
         ms1.insert(num);
     }
 ​
     for (auto num : ms1)
     {
         cout << num << " ";
     }
     cout << endl;
     // 使用find查找后删除
     ms1.erase(ms1.find(3));
     for (auto num : ms1)
     {
         cout << num << " ";
     }
     cout << endl;
     // 直接删除
     ms1.erase(3);
     for (auto num : ms1)
     {
         cout << num << " ";
     }
 ​
     return 0;
 }
 ​
 输出结果:
 0 0 1 1 2 2 3 3 3 3 3 3 4 4 5 6 6 7 8 9
 0 0 1 1 2 2 3 3 3 3 3 4 4 5 6 6 7 8 9
 0 0 1 1 2 2 4 4 5 6 6 7 8 9

如果multiset中指定数值有重复,multiset类中find()函数会找到左子树第一个值为指定值(不存在则返回其他与指定值相同的节点)的位置,返回该位置的迭代器,所以此时调用erase()函数,将find()返回的迭代器传给erase()函数,删除的就是左子树的第一个值,而如果直接调用erase()函数,传入指定值,则一次性全部删除

map类介绍与简单使用

与set类不同的是,map类是KV模型的平衡二叉树(红黑树),因为是Key_Value模型,所以map类总是以key进行排序,map也是用来存储数据的,与序列式容器(forward_list)不同的是,其里面存储的是<key, value>结构的键值对pair

用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量keyvaluekey代表键值,value表示与key对应的信息。下面是SGI版本的键值对定义:

 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) {}
 ​
    template <class U1, class U2>
    pair(const pair<U1, U2>& p) : first(p.first), second(p.second) {}
 };

map类的特点:

  1. 因为底层还是类似于二叉搜索树,但是进行了优化,所以效率为log_{2}{N}

  2. map类中的key值无法被修改,一旦插入了就没有再次修改的机会

  3. map类支持下标访问

  4. map类按照key升序排序

map类

map官方文档

简单使用实例:

map类没有直接添加key_value键值对的构造函数,所以需要使用其他方式进行内容添加

首先介绍map类中的insert()函数,与set类的insert()不同的是,map类需要使用pair对象作为参数传递给insert()函数,下面是insert()函数原型之一

 pair<iterator,bool> insert (const value_type& val);
 ​
 // 其中value_type为pair<const key_type, mapped_type>
 // key_type为第一个模版参数Key
 // mapped_type为第二个模版参数T

所以在插入数据时,首先需要一个pair对象,前面提供了pair结构的原型,其中有三种构造函数

  1. 无参构造:firstsecond给类型初始值

  2. 有参构造:给定firstsecond对应的值进行初始化

  3. 拷贝构造:使用已经存在的pair对象构造

有了pair对象的构造,结合insert()函数就可以为map类添加对象,下面提供五种方式:

#define _CRT_SECURE_NO_WARNINGS 1
 ​
 #include <iostream>
 #include <map>
 using namespace std;
 ​
 int main()
 {
     // map的五种构造方式
     
     // 1. 创建pair对象再通过insert()函数插入到map中
     pair<string, string> p1("字符串1", "字符串2");
     map<string, string> m1;
     m1.insert(p1);
 ​
     // 2. 匿名对象插入
     map<string, string> m2;
     m2.insert(pair<string, string>("字符串1", "字符串2"));
 ​
     // 3. 无explicit修饰下的隐式类型转换
     map<string, string> m3;
     m3.insert({ "字符串1", "字符串2" });
 ​
     // 4. make_pair函数
     map<string, string> m4;
     m4.insert(make_pair("字符串1", "字符串2"));
 ​
     // 5. initializer_list
     map<string, string> m5 = { {"字符串1", "字符串2"}, {"字符串3", "字符串4"} };
 ​
     return 0;
 }

上面代码中的第三种方式与下面的过程等价

 pair<string, string> p2 = { "字符串1", "字符串2" }; // 隐式类型转换
 m3.insert(p2);

以二叉搜索树中:统计水果出现的次数为例

#include <iostream>
 #include <map>
 using namespace std;
 ​
 int main()
 {
 ​
     string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };
     map<string, int> m;
     // 插入数据
     for (auto str : arr)
     {
         m.insert({str, 0});
     }
 ​
     // 迭代器遍历
     auto it = m.begin();
     while (it != m.end())
     {
         cout << (*it).first << "->" << it->second << endl;
         ++it;
     }
     cout << endl;
     
     // 查找+删除
     auto pos = m.find("苹果");
     m.erase(pos);
     auto it1 = m.begin();
     while (it1 != m.end())
     {
         cout << (*it1).first << "->" << it1->second << endl;
         ++it1;
     }
 ​
     return 0;
 }

需要注意map中的operator[]函数,如果想要实现在二叉搜索树中的计数,可以使用该函数

 #define _CRT_SECURE_NO_WARNINGS 1
 ​
 #include <iostream>
 #include <map>
 using namespace std;
 ​
 int main()
 {
 ​
     string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };
     map<string, int> m;
     for (auto str : arr)
     {
         m[str]++;
     }
 ​
     auto it = m.begin();
     while (it != m.end())
     {
         cout << it->first << "->" << it->second << endl;
         ++it;
     }
 ​
     return 0;
 }

在map类中,operator[]函数的本质是通过[]中的key查找key对应的value值,如果key不存在就插入,将value设置为对应类型的默认值,如果key存在就返回value

这个函数的调用可以类比成下面的思路:

 (*((this->insert(make_pair(k,mapped_type()))).first)).second

将其拆解为三部分:

  1. (this->insert(make_pair(k,mapped_type())))

    该部分本质是调用了一个insert()函数,在map类中insert()函数返回pair<iterator, bool>,如果插入成功证明插入的键值对一开始不存在,返回插入后位置的迭代器,并将bool类型的变量设置为true表示插入成功;如果键值对一开始存在,返回存在的键值对位置的迭代器,并将bool类型的变量设置为false表示插入失败

  2.  (*(pair<iterator, bool>.first))

    该部分本质是调用插入节点的迭代器访问该迭代器的first值,因为这个键值对中的iterator存储的成功插入或者已经存在于map中的键值对位置的迭代器,所以该迭代器指向的是一个实际的节点,即一个实际的键值对节点,解引用该节点就可以取到其中的内容

  3.  (*iterator).second // iterator表示已经插入的节点或者原有节点位置的迭代器

    该部分就是取出迭代器指向的节点中的second的值

所以,在map类中operator[]可以用于下面的行为:

  1. 不存在[]中的key,插入该key

  2. 存在[]中的key,返回key对应的value

  3. 存在[]中的key,修改key对应的value

multimap类

与map类基本相同,但是multimap类允许数据出现重复,并且multimap类不支持operator[]函数和at函数

multimap官方文档

基本使用与map类和multiset类似,不再做演示

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

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

相关文章

188数码管轮询扫描

前言 最近用到了188数码管&#xff0c;总结一下。 188数码管&#xff0c;用5个IO&#xff0c;在不借助外部驱动芯片的情况下&#xff0c;可以点亮20个灯。188数码管广泛应用于电子烟、充电器、充电宝、DVD、高级音响、工业设备控制面板、医疗器械等多个领域&#xff0c;满足不…

FPGA FIR fdatool filter designer MATLAB

位数问题 fdatool 先确定输入信号的位宽&#xff0c;比如17位在fdatool中&#xff0c;选set quantization parameters 选input/output 设置input word length 为17bit(not confirmed) fir compiler implementation 注意&#xff1a; 当设置输入位宽为16位时&#xff0c;ip核…

Java 快速入门学习 -- Day 2

Java 快速入门 Ⅱ maven&#xff08;图书管理员&#xff09;IDEA使用 maven框架 maven&#xff08;图书管理员&#xff09; maven 仓库&#xff0c;图书馆。要看书的化先从家里找&#xff08;本地仓库&#xff09;&#xff0c;本地找不到就去中央仓库或者镜像仓库找&#xff0c…

CSA笔记3-文件管理命令(补充)+vim+打包解包压缩解压缩命令

grep(-i -n -v -w) [rootxxx ~]# grep root anaconda-ks.cfg #匹配关键字所在的行 [rootxxx ~]# grep -i root anaconda-ks.cfg #-i 忽略大小写 [rootxxx ~]# grep -n root anaconda-ks.cfg #显示匹配到的行号 [rootxxx ~]# grep -v root anaconda-ks.cfg #-v 不匹配有…

记录些MySQL题集(8)

ACID原则、事务隔离级别及事务机制原理 一、事务的ACID原则 什么是事务呢&#xff1f;事务通常是由一个或一组SQL组成的&#xff0c;组成一个事务的SQL一般都是一个业务操作&#xff0c;例如聊到的下单&#xff1a;「扣库存数量、增加订单详情记录、插入物流信息」&#xff0…

AQS详解

文章目录 AQS 是什么&#xff1f;AQS 的原理是什么&#xff1f;AQS 资源共享方式总结 AQS 是什么&#xff1f; AQS 的全称为 AbstractQueuedSynchronizer &#xff0c;翻译过来的意思就是抽象队列同步器。这个类在 java.util.concurrent.locks 包下面。 AQS是一个用来构建锁和…

【操作系统】定时器(Timer)的实现

这里写目录标题 定时器一、定时器是什么二、标准库中的定时器三、实现定时器 定时器 一、定时器是什么 定时器也是软件开发中的⼀个重要组件.类似于⼀个"闹钟".达到⼀个设定的时间之后,就执行某个指定 好的代码. 定时器是⼀种实际开发中⾮常常用的组件. ⽐如⽹络通…

base SAS programming学习笔记13(Array)

1.Array array-name{dimension} <elements> array-name&#xff1a;向量名称 dimension&#xff1a;向量长度&#xff0c;默认为1&#xff1b; elements:列出变量名&#xff0c;变量名要么全是数值变量或者全是字符变量 array-name和variable不能相同&#xff1b;也不能和…

【BUG】已解决:java.lang.IllegalStateException: Duplicate key

已解决&#xff1a;java.lang.IllegalStateException: Duplicate key 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#xff0c;我是博主英杰&#xff0c;211科班出身&#xff0c;就职于医疗科技公司&#xff0c;热衷分享知识&#xff0c;武汉城市…

Java红娘婚恋相亲交友系统小程序源码

红娘婚恋相亲交友小程序&#xff1a;遇见爱情&#xff0c;从指尖开始&#x1f496; &#x1f4f1; 掌中红娘&#xff0c;随时待命 &#x1f48c; 在这个数字化时代&#xff0c;爱情也迎来了它的新舞台——“红娘婚恋相亲交友小程序”。只需轻轻一点&#xff0c;你的专属红娘就…

记录些MySQL题集(6)

MySQL 单表为什么不要超过 2000W 行&#xff1f; 数据持久化在磁盘中&#xff0c;磁盘的最小单元是扇区&#xff0c;一个扇区 0.5 KB&#xff0c;而由 8 个扇区可以构成一个文件系统块&#xff08;4K&#xff09;&#xff0c;以 InnoDB 存储引擎为例&#xff0c;一个数据页的大…

浅谈C嘎嘎类与对象

本篇文章与大家浅谈一下C嘎嘎的类与对象知识点 类的定义 关键字&#xff1a;class 语法格式&#xff1a; class 类名 { }&#xff1b;//这里的分号不能少 此外&#xff0c;class有三个属性分别是private、public、protected&#xff0c;这三个属性是干啥的&#xff0c;相…

昇思25天学习打卡营第13天|CycleGAN 图像风格迁移互换全流程解析

目录 数据集下载和加载 可视化 构建生成器 构建判别器 优化器和损失函数 前向计算 计算梯度和反向传播 模型训练 模型推理 数据集下载和加载 使用 download 接口下载数据集&#xff0c;并将下载后的数据集自动解压到当前目录下。数据下载之前需要使用 pip install dow…

如何PR到别人仓库(指定分支,无废话)

如何PR到别人仓库&#xff08;指定分支&#xff09; 记录一下&#xff0c;之前都是直接master分支&#xff0c;现在记录如何pr到别人仓库的其他分支 首先进入别人仓库然后点击fork到自己仓库 步骤&#xff08;以博主自己一个例子为例&#xff09; &#xff08;1&#xff09;…

配置和保护SSH

使用SSH访问远程命令行 描述Secure Shell SSH&#xff08;Secure Shell&#xff09; 是一种网络协议&#xff0c;用于在不安全的网络上安全地进行系统管理和数据传输。它最初由 Tatu Ylnen 于1995年设计&#xff0c;并成为保护网络服务免受攻击的标准。SSH提供了多种功能&…

prometheus+grafana应用监控配置

配置Prometheus 官方地址&#xff1a;Download | Prometheus &#xff08;wegt下载压缩包&#xff0c;解压并重命名prometheus&#xff0c;文件放于/data/prometheus即可&#xff09; 配置 service方法(文件放于 /etc/systemd/system/prometheus.service)&#xff1a; [Unit…

Windows与Ubuntu安装ffmpeg

文章目录 前言ffmpeg的简介安装ffmpegWindows下载设置环境变量 Ubuntu 总结 前言 FFmpeg是一款非常强大的开源音视频处理工具&#xff0c;它包含了众多的音视频编解码库&#xff0c;可以用于音视频的采集、编解码、转码、流化、过滤和播放等复杂的处理。在Windows系统上安装FF…

Talk|清华大学袁天远:PreSight - 利用NeRF先验帮助自动驾驶场景在线感知

本期为TechBeat人工智能社区第605期线上Talk。 北京时间7月3日(周三)20:00&#xff0c;清华大学博士生—袁天远的Talk已经准时在TechBeat人工智能社区开播&#xff01; 他与大家分享的主题是: “PreSight - 利用NeRF先验帮助自动驾驶场景在线感知”&#xff0c;他向大家介绍了新…

OBD诊断(ISO15031) 08服务

文章目录 功能简介ISO 9141-2、ISO 14230-4和SAE J1850的诊断服务定义1、请求控制车载设备请求消息&#xff08;读取支持的TID&#xff09;2、请求控制车载设备响应消息&#xff08;报告支持的TID&#xff09;3、请求控制车载设备请求消息&#xff08;读取TID值&#xff09;4、…

QTableView仿Excel表头排序和筛选

一.效果 Excel的排序和筛选弹窗如下所示 功能非常强大。不仅支持内容排序和筛选,还支持颜色的排序和筛选,而且还支持设置多种过滤条件。本文只仿最常用的内容排序和内容单过滤条件的筛选,效果如下所示。 从效果图中可以看出,表头Section中的按钮有下列六种状态 enum Butt…