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

【C++】速识map与set

本文是小编巩固自身而作,如有错误,欢迎指出!

目录

一、map和set是个啥

二、set

(1)lower_bound与upper_bound

(2)equal_range

(3)set的增删改

三、map

(1)key/value

(2)operator[]


一、map和set是个啥

在前文我们已经学习了二叉搜索树,而map和set实际上都是二叉搜索树的一种,关于二叉搜索树可以看前文:二叉搜索树https://blog.csdn.net/2401_85487070/article/details/151681422?fromshare=blogdetail&sharetype=blogdetail&sharerId=151681422&sharerefer=PC&sharesource=2401_85487070&sharefrom=from_link下面我们将其分别介绍。

二、set

在C++中,std::set 是标准模板库(STL)提供的一个容器,它基于红黑树(一种自平衡的二叉搜索树)实现,用于存储唯一元素,并且这些元素会按照一定的顺序自动排序(默认是升序)

总结来说就是三个词:中序、排序、去重

• set的声明如下,T就是set底层关键字的类型

• set默认要求T⽀持⼩于⽐较,如果不⽀持或者想按⾃⼰的需求⾛可以⾃⾏实现仿函数传给第⼆个模 版参数

• set底层存储数据的内存是从空间配置器申请的,如果需要可以⾃⼰实现内存池,传给第三个参 数。

• ⼀般情况下,我们都不需要传后两个模版参数。

• set底层是⽤红⿊树实现,增删查效率是O(logN) ,迭代器遍历是⾛的搜索树的中序,所以是有序 的。

(1)lower_bound与upper_bound

  • lower_bound:用于在一个有序的序列(如std::vectorstd::set等)中查找第一个不小于给定值的元素的位置。可以将其想象成在一排按顺序排列的书架上,找到第一本编号不小于你指定编号的书的位置。
  • upper_bound:用于在一个有序的序列中查找第一个大于给定值的元素的位置。就好像在书架上找到第一本编号大于你指定编号的书的位置。
int main() {std::set<int> v = {1, 3, 5, 7, 9, 11, 13};// 使用 lower_bound 查找第一个不小于 6 的元素auto low = std::lower_bound(v.begin(), v.end(), 6);if (low != v.end()) {std::cout << "lower_bound 找到的元素: " << *low << std::endl;}// 使用 upper_bound 查找第一个大于 6 的元素auto up = std::upper_bound(v.begin(), v.end(), 6);if (up != v.end()) {std::cout << "upper_bound 找到的元素: " << *up << std::endl;}return 0;
}

而有的同学就好奇了?这两个看起来功能差距不大,为什么要专门分开呢?,这里我们就要涉及一个新概念,multiset

std::multiset 是一种关联容器,它基于红黑树这种自平衡二叉搜索树实现。这意味着元素在容器中是有序存储的,默认按照元素的键值升序排列。

但其最大的特点就是可以存储重复元素

我们将上述代码稍作修改就可以看到

   std::set<int> v = { 1, 3, 5,6,6,6,6,7,9, 11, 13 };

(2)equal_range

equal_range 函数用于在一个已排序的范围内查找与给定键相等的所有元素。它返回一个 std::pair,其中 first 是指向第一个不小于给定键的元素的迭代器(等同于 lower_bound 的返回值),second 是指向第一个大于给定键的元素的迭代器(等同于 upper_bound 的返回值)。

int main() {std::multiset<int> ms = { 1, 2, 2, 3, 3, 3, 4 };auto range = ms.equal_range(3);for (auto it = range.first; it != range.second; ++it) {std::cout << *it << " ";}std::cout << std::endl;return 0;
}

(3)set的增删改

insert:接收一个 initializer_list 作为参数
find:找到了就返回对应元素的迭代器,没找到返回end() 

count:返回找到的个数
erase:会造成迭代器失效

int main()
{set<int> s = { 1,2,3,9,11 };// 插入s.insert({ 4,5,6 });s.insert(7);s.insert(7);s.insert(7);// 搜索s.find(7); // 找到了返回对应键的迭代器if (s.find(8) == s.end()) // 没找到返回s.end(){cout << "没找到" << endl;}// 迭代器auto it = s.begin();while (it != s.end()){cout << *it << " ";it++;}cout << endl;// it = s.begin();// s.erase(it);// cout << "迭代器失效 :" << *it << endl;multiset<int> s2 = { 1,1,1,1,0,0,0 };cout << s2.count(1) << endl; // 返回找到的个数cout << s2.count(2) << endl;}

三、map

std::map 是一种关联容器,它存储的元素是键值对(std::pair<const Key, T>),其中键(Key)是唯一的,并且容器会根据键的大小对元素进行自动排序(默认按升序排列)。

而讲到map,就得涉及一个新知识key/value

(1)key/value


  • key:只有key作为关键码,结构中只存储key,关键码即为需要搜索到的值,且key不支持修改。set就是只存储键的。
  • key/val:存储键值对key: val的,搜索和查找时,只根据key的值进行查找,可以修改key对应的val的值。map就是存储键值对的。

我们看看下面代码就可以理解

void test01()
{pair<string, string> kv1("apple", "苹果");pair<string, string> kv2("banana", "香蕉");pair<string, string> kv3("orange", "橘子");map<string, string> dicrtory = { kv1,kv2,kv3 };dicrtory.insert(make_pair("money", "软妹币"));auto it = dicrtory.begin();while (it != dicrtory.end()){//it->second = "xyz";cout << (*it).first << ":" << (*it).second << endl;++it;}cout << endl;
}

在上述代码我们就可以看到,前面的英文名就是key(不可修改),后面的中文解释就是value(可以修改)。

(2)operator[]

std::map 的 [] 运算符用于通过键来访问或插入元素。如果指定的键已经存在于 map 中,[] 运算符会返回该键对应的值的引用;如果键不存在,[] 运算符会自动插入一个新的键值对,其中键是指定的键,值是该值类型的默认构造值,然后返回这个新插入值的引用。

map第⼀个⽀持修改的⽅式时通过迭代器,迭代器遍历时或者find返回key所在的iterator修改,map 还有⼀个⾮常重要的修改接⼝operator[],但是operator[]不仅仅⽀持修改,还⽀持插⼊数据和查找数 据,所以他是⼀个多功能复合接⼝

void blogtest(){std::map<std::string, int> scores;// 插入元素scores["Alice"] = 90;// 访问已存在的元素std::cout << "Alice's score: " << scores["Alice"] << std::endl;// 访问不存在的元素,会插入默认值std::cout << "Bob's score: " << scores["Bob"] << std::endl;}

下面我们讲解一下[]的原理

在官方界面,我们可以看到[]的返回值是

看起来非常的复杂令人头疼,下面我们就解释一下

首先,我们看看红色的框,这是一个insert函数,它的返回值是一个pair<ietrator,bool>(在insert后,成功会返回指针,失败会返回false),然后我们又取了他的firsrt,即insert返回的指针(iterator),然后我们对其进行解引用得到一个pair<key,value>,到这里相信大家都知道下一步是什么了,就是取出他的value,实现了我们平时看到的[]的作用。

本次分享就到这里结束了,后续会继续更新,感谢阅读!

http://www.dtcms.com/a/391687.html

相关文章:

  • 多层感知机(MLP)
  • Linux系统诊断——拷贝日志系统
  • python中 ​实例方法​(普通方法)和 ​类方法​ 的核心差异
  • Sping AI接入deepseek-本地部署大模型-第二期
  • 数据分析-数据指标体系搭建及应用
  • 计算机专业课《大数据技术》课程导览:开启数据智能时代
  • dumpsys battery 简介
  • 从 CNN 基础到 AlexNet:计算机视觉的破局之路
  • 苏州自动化工厂1台服务器如何5人并发SolidWorks设计
  • 固态硬盘数据恢复一般多少钱?费用分析+恢复教程
  • WebRTC 探秘:构建你自己的实时视频应用
  • 在Ubuntu中离线安装miniconda3
  • Mem0 + 百度智能云向量数据库:为AI打造持久化记忆
  • MySQL 数据归档的技术困境与 Databend 解决之道
  • 2025icpc网络赛第一场The 2025 ICPC Asia East Continent Online Contest (I)
  • docker中ngnix的路径配置
  • 什么是黑板架构风格?
  • Redis 三大核心模式(主从复制 / 哨兵 / 集群):完整部署与问题解析
  • Docker生产环境容器OOM问题定位:镜像内存泄漏还是主机资源不足?
  • AcWing385. GF和猫咪的玩具——Floyd算法
  • 75、封装paddle ocr v5服务支持昇腾800 900 、800I A2、300I DUO卡推理识别
  • 【一文了解】线程的使用
  • 电力系统暂态稳定计算与单机无穷大系统建模
  • OmniGen2 - 智源研究院推出的开源多模态生成模型
  • 【故障排查:JDK8中Files.lines方法错误使用导致的Linux服务器文件描述符泄漏问题】
  • 【multisim仿真电子秒表74LS90】2022-12-15
  • v-show 和 v-if 的区别及使用场景
  • 动态二维码杜绝代签,手机端配置同步,巡检数据更可靠
  • 数据库学习MySQL系列6、MySQL入门简单练习使用
  • 交互式生成对抗网络(iGAN)