吃透C++ STL map/set:从入门到实战,新手也能轻松上手

news2026/5/14 3:18:42
文章目录前言一、先搞懂map和set是什么核心区别在哪二、set使用详解去重排序一键搞定三、map使用详解键值映射高效查找四、map和set的常见避坑点新手必看五、map/set vs 其他容器怎么选六、总结前言在C STL标准模板库中map和set是最常用的关联式容器它们底层基于红黑树一种平衡二叉搜索树实现天生具备“自动排序”和“高效检索”的特性能极大简化我们的代码开发尤其在需要快速查找、去重、排序的场景中堪称“神器”。很多新手刚接触map和set时常常混淆两者的用途什么时候用set什么时候用map它们的接口有什么区别今天这篇博客全程以“实用”为核心不搞复杂理论只讲“怎么用、用在哪、避坑点”搭配极简实战代码新手跟着敲一遍就能轻松掌握map和set的核心用法。一、先搞懂map和set是什么核心区别在哪map和set同属关联式容器底层都是红黑树因此都具备O(log₂N)的插入、查找、删除效率且元素会自动排序但两者的核心用途和存储结构完全不同这是区分它们的关键。1. 核心定义与存储结构set集合仅存储“键key”不存储“值value”且不允许重复key元素会按照key的默认规则升序自动排序。可以理解为“去重排序”的容器比如存储一个班级的学号不重复且需要有序。map映射存储“键值对key-value”key唯一value可重复元素会按照key的默认规则升序自动排序。可以理解为“字典”key是“单词”value是“释义”通过key能快速找到对应的value比如存储学生的学号key和姓名value。2. 核心区别一张表看懂特性setmap存储内容仅key键key-value键值对key是否唯一是不允许重复是不允许重复排序依据按key自动排序按key自动排序核心用途去重、排序、快速查找某个值是否存在键值映射、通过key快速获取value、排序底层结构红黑树平衡二叉搜索树红黑树平衡二叉搜索树补充STL还提供了multiset和multimap允许key重复用法和set、map基本一致仅在“key唯一性”上有差异本文重点讲解最常用的set和mapkey唯一。二、set使用详解去重排序一键搞定set的用法非常简单核心围绕“插入、查找、删除、遍历”四个操作无需手动排序插入后元素自动按升序排列且自动去重。1. 头文件与定义使用set必须包含头文件set定义时需指定存储的数据类型即key的类型默认排序规则为升序#include iostream #include set // set的头文件 using namespace std; // 定义set存储int类型默认升序 setint s; // 可选定义降序set需指定排序规则 setint, greaterint s_desc; // 降序排列2. 核心接口实战常用必掌握set的接口不多重点掌握以下6个就能应对大部分场景搭配代码示例理解更直观1插入元素insert()插入单个元素自动去重、自动排序也可插入区间内的元素。setint s; // 插入单个元素 s.insert(5); s.insert(2); s.insert(8); s.insert(2); // 重复元素插入失败不会报错 // 插入区间元素从数组插入 int arr[] {3, 7, 1}; s.insert(arr, arr 3); // 此时set中的元素1, 2, 3, 5, 7, 8自动升序、去重2查找元素find()查找指定key是否存在返回迭代器找到则返回对应元素的迭代器未找到则返回s.end()set的末尾迭代器指向元素后面的位置。setint s {1, 2, 3, 5, 7, 8}; // 查找key5 auto it s.find(5); if (it ! s.end()) { cout 找到元素 *it endl; // 输出找到元素5 } else { cout 未找到元素 endl; } // 查找key4 it s.find(4); if (it s.end()) { cout 未找到元素 endl; // 输出未找到元素 }3删除元素erase()有三种删除方式按迭代器删除、按key删除、删除区间内元素最常用的是前两种。setint s {1, 2, 3, 5, 7, 8}; // 1. 按key删除 s.erase(3); // 删除key3的元素返回删除的个数0或1 // 2. 按迭代器删除先找到元素再删除 auto it s.find(5); if (it ! s.end()) { s.erase(it); // 删除key5的元素 } // 3. 删除区间元素删除从begin到end的所有元素即清空set // s.erase(s.begin(), s.end()); // 此时set中的元素1, 2, 7, 84遍历元素迭代器/范围forset支持迭代器遍历和C11后的范围for遍历遍历顺序就是元素的排序顺序默认升序。setint s {1, 2, 7, 8}; // 1. 迭代器遍历 for (setint::iterator it s.begin(); it ! s.end(); it) { cout *it ; // 输出1 2 7 8 } cout endl; // 2. 范围for遍历C11及以上更简洁 for (auto num : s) { cout num ; // 输出1 2 7 8 } cout endl;5获取元素个数size()setint s {1, 2, 7, 8}; cout set元素个数 s.size() endl; // 输出46清空元素clear()setint s {1, 2, 7, 8}; s.clear(); // 清空所有元素 cout 清空后元素个数 s.size() endl; // 输出03. set实战场景去重排序最典型的场景对一组数据去重并排序无需手动写排序和去重逻辑set一键搞定。#include iostream #include set using namespace std; int main() { // 一组重复、无序的数据 int arr[] {5, 2, 8, 2, 3, 7, 1, 5, 9}; int n sizeof(arr) / sizeof(arr[0]); // 用set去重排序 setint s(arr, arr n); // 输出去重排序后的结果 cout 去重排序后; for (auto num : s) { cout num ; // 输出1 2 3 5 7 8 9 } return 0; }三、map使用详解键值映射高效查找map的核心是“key-value”映射key唯一且排序通过key能快速找到对应的value用法和set类似但多了对value的操作重点掌握“键值对的插入、访问、修改”。1. 头文件与定义使用map必须包含头文件map定义时需指定key和value的类型默认按key升序排序#include iostream #include map // map的头文件 using namespace std; // 定义mapkey为int学号value为string姓名默认升序 mapint, string m; // 可选定义降序map mapint, string, greaterint m_desc; // 按key降序排列2. 核心接口实战常用必掌握map的接口和set有很多相似之处但增加了对value的操作重点掌握以下7个1插入键值对insert() / 下标[]有两种常用插入方式insert()插入pair对象下标[]直接赋值更简洁注意下标[]若key不存在会自动插入该keyvalue为默认值如string为空串。mapint, string m; // 方式1insert()插入pair对象推荐可判断是否插入成功 m.insert(pairint, string(101, 张三)); m.insert(make_pair(102, 李四)); // make_pair更简洁 // 插入重复key返回pair迭代器, boolbool为false表示插入失败 auto ret m.insert(make_pair(101, 王五)); if (!ret.second) { cout key101已存在插入失败 endl; } // 方式2下标[]插入简洁但会自动创建不存在的key m[103] 赵六; // 插入key103value赵六 m[104] 孙七; // 此时map中的键值对按key升序(101,张三), (102,李四), (103,赵六), (104,孙七)2访问value下标[] / find() 迭代器两种访问方式下标[]更简洁但要注意若key不存在会自动插入该keyvalue为默认值find()更安全不会自动插入。mapint, string m {{101, 张三}, {102, 李四}, {103, 赵六}}; // 方式1下标[]访问简洁 cout 101号学生 m[101] endl; // 输出101号学生张三 cout 104号学生 m[104] endl; // key104不存在自动插入value为空串输出空 // 方式2find() 迭代器安全推荐 auto it m.find(102); if (it ! m.end()) { cout 102号学生 it-second endl; // 输出102号学生李四 } // 访问不存在的key不会自动插入 it m.find(105); if (it m.end()) { cout 105号学生不存在 endl; }注意map的迭代器指向的是“键值对pair”通过it-first访问keyit-second访问value。3修改value下标[] / find() 迭代器修改value的前提是key已存在两种方式均可下标[]更简洁。mapint, string m {{101, 张三}, {102, 李四}}; // 方式1下标[]修改 m[101] 张三丰; // 将101号的value改为张三丰 // 方式2find() 迭代器修改 auto it m.find(102); if (it ! m.end()) { it-second 李世民; // 将102号的value改为李世民 } // 输出修改后的值 cout 101号 m[101] endl; // 输出101号张三丰 cout 102号 m[102] endl; // 输出102号李世民4删除元素erase()和set用法一致支持按key删除、按迭代器删除、删除区间元素。mapint, string m {{101, 张三}, {102, 李四}, {103, 赵六}}; // 1. 按key删除 m.erase(102); // 删除key102的键值对 // 2. 按迭代器删除 auto it m.find(103); if (it ! m.end()) { m.erase(it); // 删除key103的键值对 } // 3. 删除区间元素清空map // m.erase(m.begin(), m.end()); // 此时map中仅剩余(101, 张三)5遍历元素迭代器/范围for遍历顺序按key的排序规则重点关注键值对的访问方式。mapint, string m {{101, 张三}, {102, 李四}, {103, 赵六}}; // 1. 迭代器遍历 for (mapint, string::iterator it m.begin(); it ! m.end(); it) { // it-first是keyit-second是value cout 学号 it-first 姓名 it-second endl; } // 2. 范围for遍历C11及以上 for (auto pair : m) { cout 学号 pair.first 姓名 pair.second endl; }6获取元素个数size()7清空元素clear()和set用法完全一致直接调用接口即可。mapint, string m {{101, 张三}, {102, 李四}}; cout 元素个数 m.size() endl; // 输出2 m.clear(); cout 清空后个数 m.size() endl; // 输出03. map实战场景键值映射最典型的场景存储键值对通过key快速查找value比如存储学生学号与成绩、单词与释义等。#include iostream #include map #include string using namespace std; int main() { // 存储学生学号key和成绩value mapint, int student_score; // 插入数据 student_score.insert(make_pair(101, 95)); student_score.insert(make_pair(102, 88)); student_score[103] 92; student_score[104] 79; // 查找并输出102号学生的成绩 auto it student_score.find(102); if (it ! student_score.end()) { cout 102号学生成绩 it-second endl; // 输出88 } // 修改104号学生的成绩 student_score[104] 85; cout 修改后104号学生成绩 student_score[104] endl; // 输出85 // 遍历所有学生成绩按学号升序 cout 所有学生成绩 endl; for (auto pair : student_score) { cout 学号 pair.first 成绩 pair.second endl; } return 0; }四、map和set的常见避坑点新手必看误区1map的下标[]会自动插入不存在的key——这是新手最容易踩的坑如果只是想“查找”value不要用下标[]用find()更安全避免误插入多余的key。误区2set和map可以直接修改元素——不可以set的元素是const类型不能修改否则会破坏排序和唯一性map只能修改value不能修改key修改key会破坏排序和唯一性。误区3插入重复key会报错——不会报错set和map插入重复key时插入会失败但程序不会崩溃可通过insert()的返回值判断是否插入成功。误区4set和map的迭代器可以随意加减——不可以它们的迭代器是“双向迭代器”只能用、--操作不能用1、-1和vector的随机迭代器不同。误区5底层是红黑树所以插入效率一定很高——红黑树插入时会自动平衡效率是O(log₂N)但比vector的尾插O(1)慢适合“频繁查找、删除”的场景不适合“频繁尾插”的场景。五、map/set vs 其他容器怎么选很多新手不知道什么时候用map/set什么时候用vector/list这里给出明确的选择依据需要去重、排序优先用set需要键值映射、快速通过key找value优先用map需要频繁随机访问、尾插尾删优先用vector需要频繁插入、删除非尾端且不需要排序优先用list需要允许key重复用multiset/multimap用法和set/map基本一致。六、总结map和set是C STL中最实用的关联式容器核心优势在于“自动排序”和“O(log₂N)的高效操作”底层红黑树的实现让它们无需我们手动管理排序和平衡极大提升开发效率。对于新手来说重点掌握1. 区分map和setset存key去重排序map存key-value键值映射2. 核心接口insert()、find()、erase()、size()、clear()以及map的下标访问3. 避坑点map下标[]的自动插入、不可修改set的元素和map的key。其实map和set的用法并不复杂多敲几遍实战代码熟悉接口的使用场景就能轻松掌握。它们在面试和实际开发中都非常常用学好它们能让你的代码更简洁、高效、易维护。

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

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

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…