【C++】map和set使用

前言

有了前面搜索二叉树的基础,那么这篇博客对于map和set两个容器就很好理解使用,让我们来看看map和set到底有什么特性吧

💓 个人主页:小张同学zkf

⏩ 文章专栏:C++

若有问题 评论区见📝

🎉欢迎大家点赞👍收藏⭐文章

目录

1.序列式容器和关联式容器 

2.set系列的使用

2.1set和multiset参考文档

2.2set类的介绍

2.3set的构造和迭代器

2.4set的增删查

 2.5multiset和set的差异

3.map系列的使用

3.1map和multimap参考文档

3.2map类的介绍

3.3pair类型介绍

3.4map的构造

3.5map的增删查

3.6map的数据修改

3.7multimap和map的差异


1.序列式容器和关联式容器 

前面我们已经接触过STL中的部分容器如:string、vector、list、deque、array、forward_list等,这些容器统称为序列式容器,因为逻辑结构为线性序列的数据结构,两个位置存储的值之间一般没有紧密的关联关系,如交换⼀下,他依旧是序列式容器。顺序容器中的元素是按他们在容器中的存储位置来顺序保存和访问的
关联式容器也是⽤来存储数据的,与序列式容器不同的是,关联式容器逻辑结构通常是⾮线性结构, 两个位置有紧密的关联关系,交换⼀下,他的存储结构就被破坏了。顺序容器中的元素是按关键字来保存和访问的。关联式容器有map/set系列和unordered_map/unordered_set系列。

2.set系列的使用

2.1set和multiset参考文档

链接:https://legacy.cplusplus.com/reference/set/


2.2set类的介绍

set的声明如下,T就是set底层关键字的类型
set默认要求T⽀持⼩于⽐较,如果不⽀持或者想按⾃⼰的需求⾛可以⾃⾏实现仿函数传给第⼆个模
版参数
set底层存储数据的内存是从空间配置器申请的,如果需要可以⾃⼰实现内存池,传给第三个参
数。
⼀般情况下,我们都不需要传后两个模版参数。
set底层是⽤红⿊树(下一篇博客重点介绍)实现,增删查效率是O ( logN ) ,迭代器遍历是⾛的搜索树的中序,所以是有序的。 
前⾯部分我们已经了解了vector/list等容器的使⽤,STL容器接⼝设计,⾼度相似,所以这⾥我们
就不再⼀个接⼝⼀个接⼝的介绍,⽽是直接带着⼤家看⽂档,挑⽐较重要的接⼝进⾏介绍。
template < class T , // set::key_type/value_type
class Compare = less<T>, // set::key_compare/value_compare
class Alloc = allocator<T> // set::allocator_type
> class set;

2.3set的构造和迭代器

set的构造我们关注以下⼏个接⼝即可。
set的⽀持正向和反向迭代遍历,遍历默认按升序顺序,因为底层是⼆叉搜索树,迭代器遍历⾛的中序;⽀持迭代器就意味着⽀持范围for,set的iterator和const_iterator都不⽀持迭代器修改数据,修改关键字数据,破坏了底层搜索树的结构。
// empty (1) ⽆参默认构造
explicit set ( const key_compare& comp = key_compare(),
const allocator_type& alloc = allocator_type());
// range (2) 迭代器区间构造
template < class InputIterator >
set (InputIterator first, InputIterator last,
const key_compare& comp = key_compare (),
const allocator_type& = allocator_type ());
// copy (3) 拷⻉构造
set ( const set& x);
// initializer list (5) initializer 列表构造
set (initializer_list<value_type> il,
const key_compare& comp = key_compare (),
const allocator_type& alloc = allocator_type ());
// 迭代器是⼀个双向迭代器
iterator -> a bidirectional iterator to const value_type
// 正向迭代器
iterator begin ();
iterator end ();
// 反向迭代器
reverse_iterator rbegin ();
reverse_iterator rend ();

2.4set的增删查

set的增删查关注以下⼏个接⼝即可:
Member types
key_type -> The first template parameter (T)
value_type -> The first template parameter (T)
// 单个数据插⼊,如果已经存在则插⼊失败
pair<iterator, bool > insert ( const value_type& val);
// 列表插⼊,已经在容器中存在的值不会插⼊
void insert (initializer_list<value_type> il);
// 迭代器区间插⼊,已经在容器中存在的值不会插⼊
template < class InputIterator >
void insert (InputIterator first, InputIterator last);
// 查找 val ,返回 val 所在的迭代器,没有找到返回 end()
iterator find ( const value_type& val);
// 查找 val ,返回 Val 的个数
size_type count ( const value_type& val) const ;
// 删除⼀个迭代器位置的值
iterator erase (const_iterator position);
// 删除 val val 不存在返回 0 ,存在返回 1
size_type erase ( const value_type& val);
// 删除⼀段迭代器区间的值
iterator erase (const_iterator first, const_iterator last);
// 返回⼤于等 val 位置的迭代器
iterator lower_bound ( const value_type& val) const ;
// 返回⼤于 val 位置的迭代器
iterator upper_bound ( const value_type& val) const ;

 2.5multiset和set的差异

multiset和set的使⽤基本完全类似,主要区别点在于multiset⽀持值冗余,那么
insert/find/count/erase都围绕着⽀持值冗余有所差异,具体参看下⾯的样例代码理解。
# include <iostream>
# include <set>
using namespace std;
int main ()
{
// 相⽐ set 不同的是, multiset 是排序,但是不去重
multiset< int > s = { 4 , 2 , 7 , 2 , 4 , 8 , 4 , 5 , 4 , 9 };
auto it = s. begin ();
while (it != s. end ())
{
cout << *it << " " ;
++it;
}
cout << endl;
// 相⽐ set 不同的是, x 可能会存在多个, find 查找中序的第⼀个
int x;
cin >> x;
auto pos = s. find (x);
while (pos != s. end () && *pos == x)
{
cout << *pos << " " ;
++pos;
}
cout << endl;
// 相⽐ set 不同的是, count 会返回 x 的实际个数
cout << s. count (x) << endl;
// 相⽐ set 不同的是, erase 给值时会删除所有的 x
s. erase (x);
for ( auto e : s)
{
cout << e << " " ;
}
cout << endl;
return 0 ;
}

3.map系列的使用

3.1map和multimap参考文档

链接:https://legacy.cplusplus.com/reference/map/ 


3.2map类的介绍

map的声明如下,Key就是map底层关键字的类型,T是map底层value的类型,set默认要求Key⽀持小于比较,如果不⽀持或者需要的话可以自行实现仿函数传给第⼆个模版参数,map底层存储数据的内存是从空间配置器申请的。⼀般情况下,我们都不需要传后两个模版参数。map底层是用红黑树(后面博客会出现的)实现,增删查改效率是 O ( logN ) ,迭代器遍历是⾛的中序,所以是按key有序顺序遍历的。
template < class Key , // map::key_type
class T , // map::mapped_type
class Compare = less<Key>, // map::key_compare
class Alloc = allocator<pair< const Key,T> > //
map::allocator_type
> class map;

3.3pair类型介绍

map底层的红⿊树节点中的数据,使⽤pair<Key, T>存储键值对数据。

typedef pair< const Key, T> value_type;
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 U, class V>
pair ( const pair<U,V>& pr): first(pr.first), second(pr.second)
{}
};
template < class T1 , class T2 >
inline pair<T1,T2> make_pair (T1 x, T2 y)
{
return ( pair <T1,T2>(x,y) );
}

3.4map的构造

map的构造我们关注以下⼏个接⼝即可。
map的⽀持正向和反向迭代遍历,遍历默认按key的升序顺序,因为底层是⼆叉搜索树,迭代器遍历⾛的中序;⽀持迭代器就意味着⽀持范围for,map⽀持修改value数据,不⽀持修改key数据,修改关键字数据,破坏了底层搜索树的结构
// empty (1) ⽆参默认构造
explicit map ( const key_compare& comp = key_compare(),
const allocator_type& alloc = allocator_type());
// range (2) 迭代器区间构造
template < class InputIterator >
map (InputIterator first, InputIterator last,
const key_compare& comp = key_compare (),
const allocator_type& = allocator_type ());
// copy (3) 拷⻉构造
map ( const map& x);
// initializer list (5) initializer 列表构造
map (initializer_list<value_type> il,
const key_compare& comp = key_compare (),
const allocator_type& alloc = allocator_type ());
// 迭代器是⼀个双向迭代器
iterator -> a bidirectional iterator to const value_type
// 正向迭代器
iterator begin ();
iterator end ();
// 反向迭代器
reverse_iterator rbegin ();
reverse_iterator rend ();

3.5map的增删查

map的增删查关注以下⼏个接⼝即可:
map增接⼝,插⼊的pair键值对数据,跟set所有不同,但是查和删的接⼝只⽤关键字key跟set是完全类似的,不过find返回iterator,不仅仅可以确认key在不在,还找到key映射的value,同时通过迭代还可以修改value
Member types
key_type -> The first template parameter (Key)
mapped_type -> The second template parameter (T)
value_type -> pair < const key_type,mapped_type>
// 单个数据插⼊,如果已经 key 存在则插⼊失败 ,key 存在相等 value 不相等也会插⼊失败
pair<iterator, bool > insert ( const value_type& val);
// 列表插⼊,已经在容器中存在的值不会插⼊
void insert (initializer_list<value_type> il);
// 迭代器区间插⼊,已经在容器中存在的值不会插⼊
template < class InputIterator >
void insert (InputIterator first, InputIterator last);
// 查找 k ,返回 k 所在的迭代器,没有找到返回 end()
iterator find ( const key_type& k);
// 查找 k ,返回 k 的个数
size_type count ( const key_type& k) const ;
// 删除⼀个迭代器位置的值
iterator erase (const_iterator position);
// 删除 k k 存在返回 0 ,存在返回 1
size_type erase ( const key_type& k);
// 删除⼀段迭代器区间的值
iterator erase (const_iterator first, const_iterator last);
// 返回⼤于等 k 位置的迭代器
iterator lower_bound ( const key_type& k);
// 返回⼤于 k 位置的迭代器
const_iterator lower_bound ( const key_type& k) const ;

3.6map的数据修改

前⾯我提到map⽀持修改mapped_type 数据,不⽀持修改key数据,修改关键字数据,破坏了底层搜索树的结构。
map第⼀个⽀持修改的⽅式时通过迭代器,迭代器遍历时或者find返回key所在的iterator修改,map还有⼀个⾮常重要的修改接⼝operator[],但是operator[]不仅仅⽀持修改,还⽀持插⼊数据和查找数据,所以他是⼀个多功能复合接⼝需要注意从内部实现⻆度,map这⾥把我们传统说的value值,给的是T类型,typedef为mapped_type。⽽value_type是红⿊树结点中存储的pair键值对值。⽇常使⽤我们还是习惯将这⾥的T映射值叫做value。
Member types
key_type -> The first template parameter (Key)
mapped_type -> The second template parameter (T)
value_type -> pair < const key_type,mapped_type>
// 查找 k ,返回 k 所在的迭代器,没有找到返回 end() ,如果找到了通过 iterator 可以修改 key 对应的
mapped_type
iterator find ( const key_type& k);
// ⽂档中对 insert 返回值的说明
// The single element versions (1) return a pair , with its member pair::first
set to an iterator pointing to either the newly inserted element or to the
element with an equivalent key in the map . The pair::second element in the pair
is set to true if a new element was inserted or false if an equivalent key
already existed.
// insert 插⼊⼀个 pair<key, T> 对象
// 1 、如果 key 已经在 map 中,插⼊失败,则返回⼀个 pair<iterator,bool> 对象,返回 pair 对象
first key 所在结点的迭代器, second false
// 2 、如果 key 不在在 map 中,插⼊成功,则返回⼀个 pair<iterator,bool> 对象,返回 pair 对象
first 是新插⼊ key 所在结点的迭代器, second true
// 也就是说⽆论插⼊成功还是失败,返回 pair<iterator,bool> 对象的 first 都会指向 key 所在的迭
代器
// 那么也就意味着 insert 插⼊失败时充当了查找的功能,正是因为这⼀点, insert 可以⽤来实现
operator[]
// 需要注意的是这⾥有两个 pair ,不要混淆了,⼀个是 map 底层红⿊树节点中存的 pair<key, T> ,另
⼀个是 insert 返回值 pair<iterator,bool>
pair<iterator, bool > insert ( const value_type& val);
mapped_type& operator [] ( const key_type& k);
// operator 的内部实现
mapped_type& operator [] ( const key_type& k)
{
// 1 、如果 k 不在 map 中, insert 会插⼊ k mapped_type 默认值,同时 [] 返回结点中存储
mapped_type 值的引⽤,那么我们可以通过引⽤修改返映射值。所以 [] 具备了插⼊ + 修改功能
// 2 、如果 k map 中, insert 会插⼊失败,但是 insert 返回 pair 对象的 first 是指向 key 结点的
迭代器,返回值同时 [] 返回结点中存储 mapped_type 值的引⽤,所以 [] 具备了查找 + 修改的功能
pair<iterator, bool > ret = insert ({ k, mapped_type () });
iterator it = ret.first;
return it->second;
}

3.7multimap和map的差异

multimap和map的使⽤基本完全类似,主要区别点在于multimap⽀持关键值key冗余,那么
insert/find/count/erase都围绕着⽀持关键值key冗余有所差异,这⾥跟set和multiset完全⼀样,⽐如find时,有多个key,返回中序第⼀个。其次就是multimap不⽀持[],因为⽀持key冗余,[]就只能⽀持插⼊了,不能⽀持修改。

结束语

set和map的使用总结完了,他们底层都是红黑树,后面详细介绍

OK,感谢观看!!!

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

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

相关文章

图文深入理解java对象从创建到回收都经历了什么

1. 前言&#xff1a; 每个java对象都是有生命周期的&#xff0c;就像一个人的生命一样&#xff0c;从孕育到出生到成长变老最后由归于自然。笔者认为&#xff0c;Java对象的整个生命周期可以分为两个大的阶段&#xff1a;即创建阶段和运行阶段&#xff08;包含对象的回收和消亡…

LSTM时序预测 | Python实现LSTM长短期记忆神经网络时间序列预测

本文内容&#xff1a;Python实现LSTM长短期记忆神经网络时间序列预测&#xff0c;使用的数据集为AirPassengers 目录 数据集简介 1.步骤一 2.步骤二 3.步骤三 4.步骤四 数据集简介 AirPassengers 数据集的来源可以追溯到经典的统计和时间序列分析文献。原始数据集由 Box,…

一个好的维权小程序应该是什么样的?

小程序如今为大家提供了很多的便利服务&#xff0c;且小程序的种类、功能是很多样的&#xff0c;那么对于一个好的维权小程序来说&#xff0c;其功能和设计应该紧紧围绕着用户的需求。 设计页面应该直观简单&#xff0c;功能布局让人一目了然&#xff1b;操作简单&#xff0c;…

外包干了30天,技术明显退步:一段自我觉醒与转变的旅程

在人生的长河中&#xff0c;每个人都会遇到属于自己的转折点。我也不例外。作为一个本科生&#xff0c;我于2019年通过校招踏入了南京某软件公司的大门&#xff0c;成为了一名功能测试工程师。在那个相对安逸的环境中&#xff0c;我度过了将近两年的时光。然而&#xff0c;随着…

当下的时代?

我这两天刚接触一个人,错误之皇,每做一件小事的时候他都像救命稻草一样抓着,有一天我一看,嚯,好家伙,他抱着的是已经让我仰望的参天大树了! 这个时代需要我们从无限思维的视角和做法去努力&#xff1b;它不取决于我们现在有多少&#xff0c;而取决于我们未来的成长幅度是多少&a…

Dev-C++萌新学习福利3

朝鲜球作品原创https://blog.csdn.net/2401_86502594?spm1011.2124.3001.5343 清北互联地址https://www.17ac.cn/#/ 萌新福利 作品成本6999元&#xff01;&#xff01;&#xff01; 清北互联团队编写课程&#xff0c;本人不收费。亏本买卖&#xff0c;良心服务&#xff0c;同嫂…

IP地址类型选择指南:动态IP、静态IP还是数据中心IP?

你是否曾经困惑于如何选择最适合业务需求的IP地址类型&#xff1f;面对动态IP、静态IP和数据中心IP这三种选择&#xff0c;你是否了解它们各自对你的跨境在线业务可能产生的深远影响&#xff1f; 在跨境电商领域&#xff0c;选择合适的IP类型对于业务的成功至关重要。动态IP、…

技术分享 —— JMeter接口与性能测试实战!

前言 在软件开发和运维过程中&#xff0c;接口性能测试是一项至关重要的工作。JMeter作为一款开源的Java应用&#xff0c;被广泛用于进行各种性能测试&#xff0c;包括接口性能测试。本文将详细介绍如何使用JMeter进行接口性能测试的过程和步骤。 JMeter是Apache组织开发的基…

JavaSE--全盘拿下数组的关键要领

嗨嗨大家~我来啦&#xff01;今天我们来进入数组的学习吧。 目录 一 数组的定义 1 创建数组 2 初始化数组 二 数组的使用 1 数组的访问 2 数组的遍历 2.1 for 循环打印 2.2 for-each 打印数组 三 数组是引用类型 3.1 JVM内存分布 3.2 区分基本类型与引用类型变…

Taro 中 echarts 图表使用

1 下载 echarts4taro3 yarn add echarts4taro3 或 pnpm add echarts4taro3 或 npm i echarts4taro3 --save2 图表初始化需要先加载echarts模块 import * as echarts from "echarts4taro3/lib/assets/echarts"; // 这里用了内置的&#xff0c;也可以用自定义的 echa…

TCP与UDP协议(三次握手四次挥手)

TCP与UDP 简介TCP和UDP一、TCP1.1 TCP的三次握手问题来了&#xff1a;为啥是三次握手而不是两次呢&#xff1f; 1.2建立连接后的通信过程&#xff08;丢包与乱序问题&#xff09;1.3四次挥手问题来了&#xff1a;为什么要四次挥手&#xff1f; 二、UDP 简介TCP和UDP TCP、UDP都…

SQL第16课——更新和删除数据

介绍如何利用update和delete语句进一步操作表数据。 16.1 更新数据 使用update语句。两种使用方式&#xff1a; 1. 更新表中的特定行&#xff1b; 2. 更新表中的所有行。 &#xff01;&#xff01;&#xff01;&#xff08;使用update时不要省略where子句&#xff0c;因为…

链接伪类(:hover)CSS背景图片有闪动BUG的解决方法 vue3

现象&#xff1a; hover时候&#xff0c;图片还没加载出来&#xff0c;导致边框闪烁 在Vue 3中&#xff0c;如果你遇到了使用伪类(:hover)时背景图片出现闪烁的问题&#xff0c;可能是由于浏览器的渲染机制导致的。解决这个问题的方法可能包括&#xff1a; 使用background-pos…

spark:数据的关联与合并、缓存和checkpoint

文章目录 1. 数据的关联与合并1.1 join关联1.1.1 内关联1.1.2 左关联1.1.3 右关联 1.2 Union合并 2. 缓存和checkpoint 1. 数据的关联与合并 1.1 join关联 students表数据&#xff1a; 1.1.1 内关联 内关联只返回两个 DataFrame 中在连接键上匹配的行。 # join 关联 from…

【Linux】【Jenkins】后端项目打包教程-Linux版

本次安装版本&#xff1a;2.4 1、安装git环境2、安装mavne环境2.1 下载依赖2.2、解压、赋权2.2、配置环境变量2.3、验证安装 3、jenkins-插件下载3.1、进入jenkins-->系统管理3.2、进入系统管理-->插件管理3.3、下载两个插件&#xff08;如果之前下载了&#xff0c;这里是…

Docker 的使用-01

一、Docker 设置和镜像源 1.1、设置 #查看 Docker 信息 docker version docker info#守护线程启动&#xff1a; systemctl daemon-reload 重启Docker服务&#xff1a; systemctl restart docker#关闭Docker服务 sudo systemctl stop docker#启动Docker服务 systemctl start d…

【安装JDK和Android SDK】

安装JDK和Android SDK 1 前言2 下载2.1 下载途径2.2 JDK下载和安装2.2.1 下载2.2.2 安装并配置环境变量2.2.3 验证 2.3 SDK下载和安装2.3.1 下载2.3.2 安装2.3.3 环境变量配置2.3.4 验证 1 前言 在软件开发中&#xff0c;Android应用开发通常使用Android Studio&#xff0c;但…

低成本轻量化5G网络部署redcap技术

RedCap&#xff08;Reduced Capability&#xff09;轻量化5G路由器旨在提供低功耗、成本效益高、性能较5G完整版稍微降低的解决方案。用于满足工业物联网&#xff08;IoT&#xff09;、消费电子产品和轻量级5G设备的需求。通过对5G技术进行一定程度的“功能裁剪”&#xff0c;降…

【华为】配置RIP协议

RIP&#xff08;Routing Information Protocol&#xff09;是一种内部网关协议&#xff08;IGP&#xff09;&#xff0c;主要用于小型网络中的动态路由。RIP有两个主要版本&#xff1a;‌RIPv1和‌RIPv2&#xff0c;它们之间存在一些关键区别&#xff1a; ‌分类支持‌&#xf…

医疗图像之基于UNet3+(UNet+++)的X射线图像牙齿分割

第一步&#xff1a;准备数据 X射线图像牙齿分割&#xff0c;总共有2000张 第二步&#xff1a;搭建模型 UNet3主要是参考了UNet和UNet两个网络结构。尽管UNet采用了嵌套和密集跳过连接的网络结构&#xff08;见图1(b)红色三角区域&#xff09;&#xff0c;但是它没有直接从多尺…