【C++】: STL详解 —— set和map类

目录

关联式容器

键值对

set

set的概念

set的构造函数

set的使用

map

map的概念

map的构造函数

map的使用

multiset

multimap


关联式容器

C++标准库提供了多种容器,用于高效管理和操作数据集合。这些容器可分为以下几类:

  1. 顺序容器(Sequence Containers)

  2. 关联容器(Associative Containers)

  3. 容器适配器(Container Adapters)

  4. 其他类容器类型

 顺序容器:核心是元素的线性存储,支持随机或顺序访问

容器分类容器类C++标准描述
顺序容器vectorC++98动态数组,支持快速随机访问,尾部操作高效。
listC++98双向链表,任意位置插入/删除高效,不支持随机访问。
dequeC++98双端队列,头尾插入/删除高效,支持随机访问。
arrayC++11固定大小数组,安全性优于内置数组,编译时确定大小。
forward_listC++11单向链表,节省内存,仅支持单向遍历。

 关联容器:基于键(Key)组织数据,有序容器(红黑树)与无序容器(哈希表)区分明显。

有序关联容器setC++98唯一键集合,基于红黑树,自动排序。
mapC++98键值对集合(键唯一),基于红黑树,按键排序。
multisetC++98允许重复键的集合,基于红黑树。
multimapC++98允许重复键的键值对集合,基于红黑树。
无序关联容器unordered_setC++11唯一键哈希集合,基于哈希表,元素无序。
unordered_mapC++11键值对哈希表(键唯一),基于哈希表。
unordered_multisetC++11允许重复键的哈希集合。
unordered_multimapC++11允许重复键的键值对哈希表。

容器适配器:通过限制接口实现特定数据结构(如栈、队列、堆),底层依赖其他容器。

适配器stackC++98后进先出(LIFO)结构,默认基于std::deque实现。
queueC++98先进先出(FIFO)结构,默认基于std::deque实现。
priority_queueC++98优先级队列(最大堆),默认基于std::vector实现。

 其他类容器类型:如std::stringstd::bitset,虽不是严格意义上的通用容器,但提供类似容器的操作。

其他类容器类型stringC++98字符串类,支持类似vector的操作。
bitsetC++98固定大小的位集合,用于位操作。
valarrayC++98数值计算专用数组,支持向量化操作。
spanC++20非拥有视图,提供对连续内存的轻量访问(如数组、vector等)。

键值对

键值对(Key-Value Pair) 是一种核心数据结构,用于将唯一的键(Key) 与对应的值(Value) 关联,常用于快速查找、映射或配置管理。

  • 键(Key):唯一标识符,用于快速定位值(不可重复,除非使用 multimap)。

  • 值(Value):与键关联的数据,可以是任意类型(基本类型、对象、容器等)。

键值对类型 std::pair

  • 定义std::pair<KeyType, ValueType> 是标准库中表示键值对的模板类。

  • 访问成员:通过 first(键)和 second(值)访问。

pair<string, int> p("hello", 1);
cout << p.first << p.second << endl;
// hello1

set

set的概念

set 是一个有序关联容器,存储唯一键(Key),键本身即为其值(没有额外的Value)。
元素按键的严格弱序规则(默认升序)自动排序,不允许重复键。

特性说明
唯一性所有元素唯一,插入重复值会被忽略(通过返回值可判断是否插入成功)。
自动排序元素按键值自动排序(默认升序,可自定义排序规则)。
不可修改键元素(键)在容器中不可直接修改,需先删除旧值再插入新值。
高效查找支持 O(log n) 复杂度的查找(find()count() 等操作)。
稳定迭代器插入或删除操作不会使其他元素的迭代器失效(除非指向被删除元素)。
  • set在底层是用平衡搜索树(红黑树)实现的,所以在set当中查找某个元素的时间复杂度为 logN
  • set中的元素不能被修改,因为set在底层是用平衡搜索树(红黑树)来实现的,若是对平衡搜索树(红黑树)当中某个结点的值进行了修改,那么这棵树将不再是平衡搜索树(红黑树)

set的构造函数

1、默认构造函数:创建一个空的集合,可以指定自定义的比较器(Comparator)和分配器(Allocator)。

explicit set(const Compare& comp = Compare(), const Allocator& alloc = Allocator());set<int> s1; // 默认升序排序的空集合// 自定义降序排序的比较器
struct CompareDesc 
{bool operator()(int a, int b) const { return a > b; }
};
set<int, CompareDesc> s2; // 降序排列的空集合

2、范围构造函数:通过迭代器范围 [first, last) 初始化集合,元素会被自动去重并排序。

template <class InputIterator>
set(InputIterator first, InputIterator last, const Compare& comp = Compare(), const Allocator& alloc = Allocator());vector<int> vec = {5, 2, 2, 3, 5};
// 从 vector 的迭代器范围构造,自动去重并升序排序
std::set<int> s(vec.begin(), vec.end()); // s = {2, 3, 5}

 3、拷贝构造函数:创建一个新集合,复制另一个集合的所有元素。

set(const set& other);set<int> s_original = {1, 2, 3};
set<int> s_copy(s_original); // 深拷贝,s_copy = {1, 2, 3}

4、初始化列表构造函数(C++11 起):通过初始化列表(Initializer List)直接初始化集合。

set(std::initializer_list<value_type> init, const Compare& comp = Compare(), const Allocator& alloc = Allocator());set<int> s = {3, 1, 2, 2}; // 自动去重并排序为 {1, 2, 3}

set的使用

成员函数功能
insert插入指定元素
erase删除指定元素
find查找指定元素
size获取容器中元素的个数
empty判断容器是否为空
clear清空容器
swap交换两个容器中的数据
count获取容器中指定元素值的元素个数

 示例:

#include <iostream>
#include <set>
#include <vector>
#include <algorithm> // 集合运算所需头文件
using namespace std;// 自定义比较器(按字符串长度排序)
struct LengthCompare 
{bool operator()(const string& a, const string& b) const {return a.size() < b.size();}
};int main() 
{// ------------------------ 1. 初始化与插入 ------------------------set<int> s1 = {3, 1, 2, 2}; // 去重排序: {1, 2, 3}s1.insert(5);                // 插入5s1.emplace(4);               // 原地构造插入4// ------------------------ 2. 删除与清空 ------------------------s1.erase(3);                 // 删除元素3auto it = s1.find(1);if (it != s1.end()) s1.erase(it); // 通过迭代器删除// s1.clear();               // 清空集合// ------------------------ 3. 遍历与查找 ------------------------cout << "s1: ";for (int val : s1) {          // C++11 范围for遍历cout << val << " ";       // 输出: 2 4 5}cout << endl;// 查找示例if (s1.count(4)) {cout << "4 exists in s1" << endl;}// ------------------------ 4. 自定义排序 ------------------------set<string, LengthCompare> s3 = {"apple", "banana", "cat"};// 按长度排序: "cat", "apple", "banana"cout << "s3: ";for (const auto& str : s3) {cout << str << " ";}cout << endl;return 0;
}

map

map的概念

  • 定义
    map 是一个有序关联容器,存储键值对(Key-Value Pair),其中键(Key)唯一,元素按键的严格弱序规则(默认升序)自动排序。
    每个元素是一个 std::pair<const Key, Value>,键不可修改,值可以修改。

  • 底层实现
    基于红黑树(Red-Black Tree,自平衡二叉搜索树),保证插入、删除和查找的时间复杂度为 O(log n)

特性说明
键唯一性所有键唯一,插入重复键会被忽略(可通过返回值判断是否成功)。
自动排序元素按键自动排序(默认升序,可自定义排序规则)。
不可修改键键在容器中不可直接修改,需先删除旧键值对再插入新键。
高效查找支持 O(log n) 复杂度的查找(find()count() 等操作)。
稳定迭代器插入或删除操作不会使其他元素的迭代器失效(除非指向被删除元素)。

map的构造函数

1、默认构造函数:创建一个空的 map,可指定自定义的比较器(Comparator)和分配器(Allocator)。

explicit map(const Compare& comp = Compare(), const Allocator& alloc = Allocator());map<int, string> m1; // 空map,默认按键升序排序// 自定义按字符串长度排序的比较器
struct KeyCompare {bool operator()(const string& a, const string& b) const {return a.size() < b.size();}
};
map<string, int, KeyCompare> m2; // 键按长度排序的空map

2、范围构造函数:通过迭代器范围 [first, last) 初始化 map,键值对会被自动去重并排序。

template <class InputIterator>
map(InputIterator first, InputIterator last, const Compare& comp = Compare(), const Allocator& alloc = Allocator());vector<pair<int, string>> vec = {{3, "Alice"}, {1, "Bob"}, {3, "Charlie"}};// 从vector的迭代器构造,自动去重并按键升序排序
map<int, string> m3(vec.begin(), vec.end()); // {1: "Bob", 3: "Alice"}

3、拷贝构造函数:深拷贝另一个 map 的所有键值对。

map(const map& other);map<int, string> m_original = {{1, "A"}, {2, "B"}};
map<int, string> m_copy(m_original); // 深拷贝,m_copy = {1: "A", 2: "B"}

4、初始化列表构造函数(C++11 起):通过初始化列表直接初始化 map

map(initializer_list<value_type> init, const Compare& comp = Compare(), const Allocator& alloc = Allocator());map<int, string> m5 = {{3, "Alice"}, {1, "Bob"}, {3, "Charlie"}}; // 去重后 {1: "Bob", 3: "Alice"}// 自定义降序排序
map<int, string, greater<int>> m6 = {{3, "A"}, {1, "B"}}; // {3: "A", 1: "B"}

注意事项

  1. 键的唯一性:插入重复键时,insert 会失败,operator[] 会覆盖原有值。

  2. 自定义比较器:需满足严格弱序规则(例如不能定义 <= 作为比较逻辑)。

  3. 性能权衡:若无需有序性,优先使用 unordered_map(哈希表实现,平均 O(1) 操作)。

map的使用

接口分类接口名称作用
插入操作insert插入键值对,返回插入结果(迭代器 + 是否成功)。
emplace原地构造键值对,避免临时对象拷贝。
operator[]通过键访问值(若键不存在,插入默认值并返回引用)。
删除操作erase删除指定键或迭代器范围内的键值对。
clear清空所有键值对。
查找与访问find查找键,返回迭代器(未找到返回 end())。
count返回键的数量(0 或 1)。
contains (C++20)检查键是否存在,返回布尔值。
at安全访问值(键不存在时抛出异常)。
容量查询empty检查容器是否为空。
size返回键值对数量。
迭代器begin / end获取正向迭代器(按键升序)。
rbegin / rend获取反向迭代器(按键降序)。

 示例:

#include <iostream>
#include <map>
#include <string>
using namespace std;int main() 
{map<int, string> m;// 插入操作m.insert({1, "Alice"});m.emplace(2, "Bob");      // 原地构造m[3] = "Charlie";         // operator[] 插入// 删除操作m.erase(1);               // 删除键1// m.clear();             // 清空所有元素// 查找与访问auto it = m.find(3);if (it != m.end()) {cout << "键3的值: " << it->second << endl;}// operator[] 的副作用(自动插入默认值)cout << "m[4]: " << m[4] << endl; // 输出空字符串(自动插入{4, ""})// 遍历(C++17 结构化绑定)cout << "所有键值对:" << endl;for (const auto& [key, value] : m) {cout << key << ": " << value << endl;}// 容量查询cout << "元素数量: " << m.size() << endl;cout << "是否为空: " << (m.empty() ? "是" : "否") << endl;return 0;
}

multiset

multiset容器与set容器的底层实现一样,都是平衡搜索树(红黑树),multiset容器和set容器的唯一区别就是,multiset允许键值冗余,即multiset容器当中存储的元素是可以重复的。

特性std::setstd::multiset
键的唯一性键唯一,不允许重复允许重复键
插入操作插入重复键时失败(返回 pair<iterator, bool>总是插入成功(返回 iterator
查找与计数count(key) 返回 0 或 1count(key) 可返回 >=0 的任意值
底层实现红黑树(自平衡二叉搜索树)红黑树(自平衡二叉搜索树)
时间复杂度插入、删除、查找均为 O(log n)同 set
典型应用场景需要唯一键的有序集合(如用户ID集合)允许重复的有序集合(如统计成绩分布)
  • 选择 set:需要保证键唯一性且需要有序遍历的场景(如字典、配置表)。

  • 选择 multiset:允许重复键且需要统计频率或保留重复数据的场景(如日志时间戳记录、投票统计)。

 

multimap

multimap容器与map容器的底层实现一样,也都是平衡搜索树(红黑树),multimap容器和map容器的区别,multimap允许键值冗余,即multimap容器当中存储的元素是可以重复的

特性std::mapstd::multimap
键的唯一性键唯一,不允许重复允许重复键
插入操作插入重复键时覆盖原有值(operator[])或失败(insert总是插入成功,允许多个相同键的键值对共存
查找与访问operator[] 直接通过键访问值(键不存在时插入)没有 operator[],必须通过迭代器访问
查找结果find(key) 返回单个迭代器find(key) 返回第一个匹配键的迭代器
键值对数量每个键对应唯一值一个键可对应多个值
典型应用场景字典、配置表(键唯一)一对多映射(如学生ID对应多门课程成绩)
  • 选择 map:需要键唯一且直接通过键访问值(如用户ID到用户名的映射)。

  • 选择 multimap:允许键重复且需处理一对多关系(如订单ID对应多个商品)。

  • 关键区别

    • map 的键唯一,支持 operator[]

    • multimap 允许键重复,需用迭代器或 equal_range 处理多个值。

 

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

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

相关文章

DeepSeek:构筑大数据平台底座的最优解

一、大数据平台底座的重要性 在数字化浪潮席卷全球的当下,数据已成为企业乃至整个社会最具价值的资产之一 。大数据平台底座作为数据处理和业务支撑的核心枢纽,其重要性不言而喻,犹如大厦的基石,关乎整个数据生态系统的稳定与发展。 从数据处理角度来看,随着互联网、物联…

Minix OS的配置 SSH C程序编译

Minix3的下载 官网&#xff1a;https://www.minix3.org/ 安装 平台&#xff1a;VMware 开机后进入系统使用setup命令来配置和安装尽量配置一个DNS服务器&#xff0c;比如8.8.8.8 SSH 安装&#xff1a;pkgin install openssh 修改配置文件&#xff0c;需要&#xff1a; 修…

ubuntu20 安装python2

1. 确保启用了 Universe 仓库 在某些情况下&#xff0c;python2-minimal 包可能位于 Universe 仓库中。你可以通过以下命令启用 Universe 仓库并更新软件包列表&#xff1a; bash复制 sudo add-apt-repository universe sudo apt update 然后尝试安装&#xff1a; bash复制…

STM32---FreeRTOS中断管理试验

一、实验 实验目的&#xff1a;学会使用FreeRTOS的中断管理 创建两个定时器&#xff0c;一个优先级为4&#xff0c;另一个优先级为6&#xff1b;注意&#xff1a;系统所管理的优先级范围 &#xff1a;5~15 现象&#xff1a;两个定时器每1s&#xff0c;打印一段字符串&#x…

docker利用docker-compose-gpu.yml启动RAGFLOW,文档解析出错【亲测已解决】

0.问题说明 想要让RAGFLOW利用GPU资源跑起来&#xff0c;可以选择docker-compose-gpu.yml启动。&#xff08;但是官网启动案例是86平台的不是NVIDIA GPU的&#xff0c;docker-compose-gpu.yml又是第三方维护&#xff0c;所以稍有问题&#xff09; 1.问题 docker利用docker-c…

【AI深度学习网络】卷积神经网络(CNN)入门指南:从生物启发的原理到现代架构演进

深度神经网络系列文章 【AI深度学习网络】卷积神经网络&#xff08;CNN&#xff09;入门指南&#xff1a;从生物启发的原理到现代架构演进【AI实践】基于TensorFlow/Keras的CNN&#xff08;卷积神经网络&#xff09;简单实现&#xff1a;手写数字识别的工程实践 引言 在当今…

【ThreeJS Basics 06】Camera

文章目录 Camera 相机PerspectiveCamera 透视相机正交相机用鼠标控制相机大幅度转动&#xff08;可以看到后面&#xff09; 控制组件FlyControls 飞行组件控制FirstPersonControls 第一人称控制PointerLockControls 指针锁定控制OrbitControls 轨道控制TrackballControls 轨迹球…

Linux | Ubuntu 与 Windows 双系统安装 / 高频故障 / UEFI 安全引导禁用

注&#xff1a;本文为 “buntu 与 Windows 双系统及高频故障解决” 相关文章合辑。 英文引文&#xff0c;机翻未校。 How to install Ubuntu 20.04 and dual boot alongside Windows 10 如何将 Ubuntu 20.04 和双启动与 Windows 10 一起安装 Dave’s RoboShack Published in…

在 C++ 中,通常会使用 `#define` 来定义宏,并通过这种方式发出警告或提示。

在 C++ 中,通常会使用 #define 来定义宏,并通过这种方式发出警告或提示。 如何实现 GBB_DEPRECATED_MSG 宏: 你可以通过以下方式定义一个宏,显示弃用警告: #include <iostream>// 定义一个宏,用来打印弃用警告 #define GBB_DEPRECATED_MSG(msg

el-tree右键节点动态位置展示菜单;el-tree的节点图片动态根据节点属性color改变背景色;加遮罩层(opacity)

一、el-tree右键节点动态位置展示菜单 关键:@node-contextmenu="handleRightClick"与@node-click=“handleNodeClick” <div class="content"><el-tabs class="tabs" @tab-click="handleClick" v-model="Modal"…

Leetcode 378-有序矩阵中第 K 小的元素

给你一个 n x n 矩阵 matrix &#xff0c;其中每行和每列元素均按升序排序&#xff0c;找到矩阵中第 k 小的元素。 请注意&#xff0c;它是 排序后 的第 k 小元素&#xff0c;而不是第 k 个 不同 的元素。 你必须找到一个内存复杂度优于 O(n2) 的解决方案。 示例 1&#xff1…

【二.提示词工程与实战应用篇】【3.Prompt调优:让AI更懂你的需求】

最近老张在朋友圈秀出用AI生成的国风水墨画,隔壁王姐用AI写了份惊艳全场的年终总结,就连楼下小卖部老板都在用AI生成营销文案。你看着自己跟AI对话时满屏的"我不太明白您的意思",是不是怀疑自己买了台假电脑?别慌,这可能是你的打开方式不对。今天咱们就聊聊这个…

UNIAPP前端配合thinkphp5后端通过高德API获取当前城市天气预报

如何通过 UniApp 前端项目与 ThinkPHP5 后端结合高德天气 API 获取天气预报信息。我们将分为前端和后端两部分进行实现。以下是一个完整的代码. 一、项目结构 project/ ├── frontend/ (UniApp 项目) │ ├── pages/ │ │ └── weather/ │ │ ├── in…

蓝桥杯C组真题——巧克力

题目如下 思路 代码及解析如下 谢谢观看

CSDN博客写作教学(五):从写作到个人IP的体系化构建(完结篇)

导语 (第一篇)Markdown编辑器基础 (第二篇)Markdown核心语法 (第三篇)文章结构化思维 (第四篇)标题优化与SEO实战 通过前四篇教程,你已掌握技术写作的“术”——排版、标题、流量与数据。但真正的价值在于将技能升维为“道”:用技术博客为支点,撬动个人品牌与职业发…

Elasticsearch简单学习

1、依赖的导入 <!--ES依赖--> <dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-high-level-client</artifactId> </dependency>2、客户端链接 RestHighLevelClient client new RestHigh…

macOS Sequoia 15.3 M3 Pro芯片 iOS 开发环境配置记录(最新)

进行如下工作之前首先确保终端已翻墙&#xff0c;在ClashX选择“复制终端代理命令”&#xff0c;在终端进行粘附并执行。 安装 homebrew Homebrew 是 Mac 平台的一个包管理工具&#xff0c;提供了许多Mac下没有的Linux工具等。 /bin/bash -c "$(curl -fsSL https://raw…

迷你世界脚本组队接口:Team

组队接口&#xff1a;Team 彼得兔 更新时间: 2023-04-26 10:19:04 具体函数名及描述如下: 序号 函数名 函数描述 1 getNumTeam(...) 当前队伍数量 2 getTeamPlayerNum(...) 获取指定队伍玩家数量 3 getTeamPlayers(...) 获取指定队伍玩家 4 random…

使用 Deepseek + kimi 快速生成PPT

前言 最近看到好多文章和视频都在说&#xff0c;使用 Deepseek 和 kimi 能快速生成精美的 ppt&#xff0c;毕竟那都是别人说的&#xff0c;只有自己尝试一次才知道结果。 具体操作 第一步&#xff1a;访问 deepseek 我们访问 deepseek &#xff0c;把我们想要输入的内容告诉…

初始提示词(Prompting)

理解LLM架构 在自然语言处理领域&#xff0c;LLM&#xff08;Large Memory Language Model&#xff0c;大型记忆语言模型&#xff09;架构代表了最前沿的技术。它结合了存储和检索外部知识的能力以及大规模语言模型的强大实力。 LLM架构由外部记忆模块、注意力机制和语…