C++—— set、map、multiset、multimap的介绍及使用

目录

关联式容器

关联式容器的特点和使用场景

树形结构与哈希结构 

树形结构

哈希结构

键值对 

set

 set的介绍

set的定义方式

 set的使用

multiset

map 

map的介绍

map的定义方式

map的使用

multimap 


关联式容器

C++标准模板库(STL)中的关联式容器(Associative Containers)是一类根据键值对元素进行存储和操作的数据结构。它们允许快速查找、插入和删除操作,并且通常是基于树或哈希表实现的。C++ STL中的关联式容器包括四种主要类型:

  1. std::setstd::multiset

    • std::set 是一种集合,其中每个元素是唯一的,按特定顺序排序。
    • std::multisetstd::set 类似,但允许重复元素。
    • 这两种容器通常使用红黑树等平衡二叉搜索树实现,因此其查找、插入和删除操作的时间复杂度为 O(log n)。
  2. std::mapstd::multimap

    • std::map 是一种关联数组,其中每个元素都是一个键-值对,键是唯一的,按特定顺序排序。
    • std::multimapstd::map 类似,但允许键重复。
    • 这两种容器也通常使用平衡二叉搜索树实现,其查找、插入和删除操作的时间复杂度同样为 O(log n)。
  3. std::unordered_setstd::unordered_multiset

    • std::unordered_set 是一种无序集合,其中每个元素是唯一的,元素无特定顺序。
    • std::unordered_multisetstd::unordered_set 类似,但允许重复元素。
    • 这两种容器使用哈希表实现,因此其平均情况下的查找、插入和删除操作时间复杂度为 O(1)。
  4. std::unordered_mapstd::unordered_multimap

    • std::unordered_map 是一种无序关联数组,其中每个元素是一个键-值对,键是唯一的,元素无特定顺序。
    • std::unordered_multimapstd::unordered_map 类似,但允许键重复。
    • 这两种容器也使用哈希表实现,其平均情况下的查找、插入和删除操作时间复杂度为 O(1)。

关联式容器的特点和使用场景

  1. 有序关联容器(setmultisetmapmultimap

    • 排序:元素按照键的顺序排列,可以方便地进行范围查询。
    • 使用场景:需要按顺序访问元素或进行范围查询时,例如实现有序字典或集合。
  2. 无序关联容器(unordered_setunordered_multisetunordered_mapunordered_multimap

    • 无序:元素无特定顺序,通过哈希值快速访问。
    • 使用场景:关注查找、插入和删除的平均时间效率,而不在乎元素顺序时,例如实现哈希表或快速查找的数据结构。

树形结构与哈希结构 

树形结构

树形结构常用于实现有序关联容器,如 std::setstd::multisetstd::mapstd::multimap。具体来说,这些容器通常采用平衡二叉搜索树(如红黑树)来实现。以下是树形结构的一些关键点:

  1. 自动排序:元素按键值自动排序,支持有序遍历。
  2. 平衡性:红黑树等平衡二叉树保证了树的高度在O(log n)范围内,从而确保查找、插入和删除操作的时间复杂度为O(log n)。
  3. 复杂性:相对于哈希表实现,树形结构的插入和删除操作更为复杂,需要维护树的平衡。

适用场景

  • 需要按顺序访问或处理数据,例如范围查询。
  • 需要查找键的前驱或后继等顺序关系操作。

哈希结构

哈希结构用于实现无序关联容器,如 std::unordered_setstd::unordered_multisetstd::unordered_mapstd::unordered_multimap。这些容器基于哈希表来实现。以下是哈希结构的一些关键点:

  1. 无序存储:元素无特定顺序,基于哈希值进行存储。
  2. 快速访问:平均情况下,查找、插入和删除操作的时间复杂度为O(1)。
  3. 哈希冲突:需要处理哈希冲突,一般采用链地址法或开放地址法等策略。

适用场景

  • 更关注操作的平均时间效率,而不在乎元素的顺序。
  • 大量频繁的查找、插入和删除操作,例如实现哈希表或集合。

 

键值对 

  键值对是用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量key和value,key代表键值,value表示与key对应的信息。

  比如我们若是要建立一个英译汉的字典,那么该字典中的英文单词与其对应的中文含义就是一一对应的关系,即通过单词可以找到与其对应的中文含义。

在SGI-STL中关于键值对的定义如下:

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){}
};

set

 set的介绍

1.set是按照一定次序存储元素的容器,使用set的迭代器遍历set中的元素,可以得到有序序列。

2.set当中存储元素的value都是唯一的,不可以重复,因此可以使用set进行去重。

3.与map/multimap不同,map/multimap中存储的是真正的键值对<key, value>,set中只放value,但在底层实际存放的是由<value, value>构成的键值对,因此在set容器中插入元素时,只需要插入value即可,不需要构造键值对。

4.set中的元素不能被修改,因为set在底层是用二叉搜索树来实现的,若是对二叉搜索树当中某个结点的值进行了修改,那么这棵树将不再是二叉搜索树。

5.在内部,set中的元素总是按照其内部比较对象所指示的特定严格弱排序准则进行排序。当不传入内部比较对象时,set中的元素默认按照小于来比较。

6.set容器通过key访问单个元素的速度通常比unordered_set容器慢,但set容器允许根据顺序对元素进行直接迭代。

7.set在底层是用平衡搜索树(红黑树)实现的,所以在set当中查找某个元素的时间复杂度为logN。

set的定义方式

方式一: 构造一个某类型的空容器。

set<int> s1; //构造int类型的空容器

方式二: 拷贝构造某类型set容器的复制品。 

set<int> s2(s1); //拷贝构造int类型s1容器的复制品

 方式三: 使用迭代器拷贝构造某一段内容。

string str("abcdef");
set<char> s3(str.begin(), str.end()); //构造string对象某段区间的复制品

方式四: 构造一个某类型的空容器,比较方式指定为大于。

set < int, greater<int>> s4; //构造int类型的空容器,比较方式指定为大于

 set的使用

set当中常用的成员函数如下:

set当中迭代器相关函数如下:

 

使用示例: 

#include <iostream>
#include <set>int main() {// 创建一个整数类型的set容器std::set<int> mySet;// 插入一些元素到set中mySet.insert(5);mySet.insert(3);mySet.insert(8);mySet.insert(2);// 使用迭代器遍历容器并输出元素(正向遍历)std::cout << "使用迭代器正向遍历容器:" << std::endl;for (auto it = mySet.begin(); it != mySet.end(); ++it) {std::cout << *it << " ";}std::cout << std::endl;// 删除一个元素mySet.erase(3);// 使用范围 for 循环遍历容器并输出元素std::cout << "使用范围 for 循环正向遍历容器:" << std::endl;for (const auto& elem : mySet) {std::cout << elem << " ";}std::cout << std::endl;// 检查集合中是否包含特定元素int target = 8;if (mySet.count(target)) {std::cout << "集合包含 " << target << std::endl;} else {std::cout << "集合不包含 " << target << std::endl;}// 获取集合的大小std::cout << "集合的大小:" << mySet.size() << std::endl;// 清空集合mySet.clear();// 检查集合是否为空if (mySet.empty()) {std::cout << "集合为空" << std::endl;} else {std::cout << "集合不为空" << std::endl;}// 向空集合中插入一些元素mySet.insert(10);mySet.insert(20);mySet.insert(30);// 使用反向迭代器遍历容器并输出元素(反向遍历)std::cout << "使用反向迭代器反向遍历容器:" << std::endl;for (auto rit = mySet.rbegin(); rit != mySet.rend(); ++rit) {std::cout << *rit << " ";}std::cout << std::endl;return 0;
}

multiset

    multiset容器与set容器的底层实现一样,都是平衡搜索树(红黑树),其次,multiset容器和set容器所提供的成员函数的接口都是基本一致的,这里就不再列举了,multiset容器和set容器的唯一区别就是,multiset允许键值冗余,即multiset容器当中存储的元素是可以重复的。

#include <iostream>
#include <set>int main() {// 创建一个允许重复元素的 multiset 容器std::multiset<int> ms;// 插入一些元素到 multiset 中ms.insert(1);ms.insert(4);ms.insert(3);ms.insert(3);ms.insert(2);ms.insert(2);ms.insert(3);// 使用范围 for 循环遍历容器并输出元素for (auto e : ms) {std::cout << e << " ";}std::cout << std::endl; // 输出:1 2 2 3 3 3 4return 0;
}

由于multiset容器允许键值冗余,因此两个容器中成员函数find和count的意义也有所不同:

 

map 

map的介绍

1.map是关联式容器,它按照特定的次序(按照key来比较)存储键值key和值value组成的元素,使用map的迭代器遍历map中的元素,可以得到有序序列。

2.在map中,键值key通常用于排序和唯一地标识元素,而值value中存储与此键值key关联的内容。键值key和值value的类型可能不同,并且在map的内部,key与value通过成员类型value_type绑定在一起,并取别名为pair。

3.map容器中元素的键值key不能被修改,但是元素的值value可以被修改,因为map底层的二叉搜索树是根据每个元素的键值key进行构建的,而不是值value。

4.在内部,map中的元素总是按照键值key进行比较排序的。当不传入内部比较对象时,map中元素的键值key默认按照小于来比较。

5.map容器通过键值key访问单个元素的速度通常比unordered_map容器慢,但map容器允许根据顺序对元素进行直接迭代。

6.map容器支持下标访问符,即在[]中放入key,就可以找到与key对应的value。

7.map在底层是用平衡搜索树(红黑树)实现的,所以在map当中查找某个元素的时间复杂度为logN。

map的定义方式

方式一: 指定key和value的类型构造一个空容器。

map<int, double> m1; //构造一个key为int类型,value为double类型的空容器

方式二: 拷贝构造某同类型容器的复制品。 

map<int, double> m2(m1); //拷贝构造key为int类型,value为double类型的m1容器的复制品

方式三: 使用迭代器拷贝构造某一段内容。

map<int, double> m3(m2.begin(), m2.end()); //使用迭代器拷贝构造m2容器某段区间的复制品

方式四: 指定key和value的类型构造一个空容器,key比较方式指定为大于。

map<int, double, greater<int>> m4; //构造一个key为int类型,value为double类型的空容器,key比较方式指定为大于

map的使用

map的插入 map的查找 map的删除 map的[ ]运算符重载 map的迭代器 

#include <iostream>
#include <map>int main() {// 创建一个键为整数,值为字符串的 map 容器std::map<int, std::string> myMap;// 插入元素到 map 中myMap.insert(std::make_pair(1, "One"));myMap.insert(std::make_pair(2, "Two"));myMap.insert(std::make_pair(3, "Three"));// 查找 map 中的元素int keyToFind = 2;auto it = myMap.find(keyToFind);if (it != myMap.end()) {std::cout << "键为 " << keyToFind << " 的值为:" << it->second << std::endl;} else {std::cout << "键为 " << keyToFind << " 的元素未找到" << std::endl;}// 删除 map 中的元素int keyToDelete = 1;myMap.erase(keyToDelete);// 使用 [] 运算符向 map 中插入或访问元素myMap[4] = "Four";// 使用迭代器遍历 map 并输出键值对std::cout << "遍历 map:" << std::endl;for (auto it = myMap.begin(); it != myMap.end(); ++it) {std::cout << "键:" << it->first << " 值:" << it->second << std::endl;}return 0;
}

map的其他成员函数

除了上述成员函数外,map当中还有如下几个常用的成员函数:

#include <iostream>
#include <string>
#include <map>int main() {// 创建一个 map 容器,键为整数,值为字符串std::map<int, std::string> myMap;// 插入一些键值对到 map 中myMap.insert(std::make_pair(2, "two"));myMap.insert(std::make_pair(1, "one"));myMap.insert(std::make_pair(3, "three"));// 获取容器中元素的个数std::cout << "容器中元素的个数:" << myMap.size() << std::endl; // 输出:3// 容器中 key 值为 2 的元素个数std::cout << "容器中 key 值为 2 的元素个数:" << myMap.count(2) << std::endl; // 输出:1// 清空容器myMap.clear();// 容器判空std::cout << "容器是否为空:" << myMap.empty() << std::endl; // 输出:1// 创建一个临时的 map 容器,并交换数据std::map<int, std::string> tmpMap;myMap.swap(tmpMap);return 0;
}

multimap 

    multimap容器与map容器的底层实现一样,也都是平衡搜索树(红黑树),其次,multimap容器和map容器所提供的成员函数的接口都是基本一致的,这里也就不再列举了,multimap容器和map容器的区别与multiset容器和set容器的区别一样,multimap允许键值冗余,即multimap容器当中存储的元素是可以重复的。

#include <iostream>
#include <string>
#include <map>int main() {// 创建一个 multimap 容器,键为整数,值为字符串std::multimap<int, std::string> mm;// 插入一些键值对到 multimap 中(允许重复键)mm.insert(std::make_pair(2, "two"));mm.insert(std::make_pair(2, "double"));mm.insert(std::make_pair(1, "one"));mm.insert(std::make_pair(3, "three"));// 使用范围 for 循环遍历 multimap 并输出键值对for (const auto& e : mm) {std::cout << "<" << e.first << "," << e.second << "> ";}std::cout << std::endl; // 输出:<1,one> <2,two> <2,double> <3,three>return 0;
}

 由于multimap容器允许键值冗余,因此两个容器中成员函数find和count的意义也有所不同:

其次,由于multimap容器允许键值冗余,调用[ ]运算符重载函数时,应该返回键值为key的哪一个元素的value的引用存在歧义,因此在multimap容器当中没有实现[ ]运算符重载函数。 

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

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

相关文章

AI必然趋势下,产品经理未来何在?路怎么走?

AI已经普遍运用到产品经理的日常工作中了。让它写个需求分析、做个PRD不在话下… 因为AI&#xff0c;也能经常听到有人在谈论&#xff1a;产品经理未来是否会被取代&#xff1f; 未来&#xff0c;产品经理的路该往哪走、怎么走&#xff1f; 未来&#xff0c;产品经理职业规划…

瑞芯微RV1126——ffmpeg环境搭建

本篇文章来介绍一下&#xff0c;在ubuntu上搭建一个比较完整的ffmpeg环境需要的步骤以及流程。为后期将我们开发的应用程序移植到RV1126开发板上做准备。 在安装ffmpeg之前&#xff0c;为了方便后续的操作&#xff0c;我们可以先搭建好samba服务器。所以本节将分为两个部分&am…

AI多模态「六边形战士」,原创音乐、1分钟百页PPT、抖音爆款……

2024年AI行业最大的看点是什么&#xff1f; 那一定是多模态AI应用。 大模型发展到今天这个阶段&#xff0c;文本处理已经是各家大模型的必备技能了&#xff0c;对音频、视觉等多模态的理解和应用才是下一个阶段大模型比拼的赛道。 3.5研究测试&#xff1a;hujiaoai.cn 4研究测…

Golang单元测试

文章目录 传统测试方法基本介绍主要缺点 单元测试基本介绍测试函数基准测试示例函数 传统测试方法 基本介绍 基本介绍 代码测试是软件开发中的一项重要实践&#xff0c;用于验证代码的正确性、可靠性和预期行为。通过代码测试&#xff0c;开发者可以发现和修复潜在的错误、确保…

Python实现数据可视化效果图总结

一、JSON格式 JSON是一种轻量级的数据交互格式。可以按照JSON指定的格式去组织和封装数据。 JSON本质上是一个带有特定格式的字符串 Json格式 JSON数据格式在Python中可以是字典、又可以是列表中嵌套着字典的格式。 Pyhton数据和Json数据相互转化 二、pyecharts模块 如果想…

二叉排序树的创建

二叉排序树就是节点经过排序构建起的二叉树&#xff0c;其有以下性质&#xff1a; 1. 若它的左子树不为空&#xff0c;则左子树上所有节点的值均小于它的根节点的值。 2. 若它的右子树不为空&#xff0c;则右子树上所有节点的值均大于它的根节点的值。 3. 它的左、右子树也分…

Springboot零星知识点1

1、请求路径的组成 2、多个环境配置文件 3、对 自定义的属性 增加文字描述&#xff0c;而且IDEA不会警告 4、读取属性值的两种方式 5、东东

【linux】docker下nextcloud安装人脸识别插件

一、插件源码地址&#xff1a; GitCode - 开发者的代码家园 二、插件官网地址&#xff1a; Releases - Face Recognition - Apps - App Store - Nextcloud 三、插件安装教程&#xff1a; 1、查看本地nextcloud版本号 http://ipAddress:8080/settings/admin/overview 2、找…

深入解析:如何高效地更新Python字典

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、引言 二、修改字典中的值 三、向字典中添加键值对 四、更新字典的两种方法总结 五、…

浏览器的一些功能

1.改主页面 点浏览器右上角的三个点也就是一个... 点了设置 你可以在这里改它的颜色 还有页面 一些有意思的网站: sandspiel像素风格游戏 趣味互动游戏&#xff1a;请画一个小人 (webhek.com)​​​​​​ 2018 - makemepulse解压游戏 Layered Water (vlucendo.com)水模…

【C++项目】实时聊天的在线匹配五子棋对战游戏

目录 项目介绍 开发环境 核心技术 项目前置知识点介绍 Websocketpp 1. WebSocket基本认识 2. WebSocket协议切换原理解析 3. WebSocket报文格式 4. Websocketpp介绍 5. 搭建一个简单WebSocket服务器 JsonCpp 1. Json格式的基本认识 2. JsonCpp介绍 3. 序列化与反序…

基于地理坐标的高阶几何编辑工具算法(3)——相离面吸附

文章目录 工具步骤应用场景算法输入算法输出算法示意图算法原理 工具步骤 点击面&#xff0c;点击“相离面吸附”工具&#xff0c;绘制一个面&#xff0c;双击结束后&#xff0c;与所有相交的面进行吸附 应用场景 为了让相离的两个几何面在空间上相邻&#xff0c;使用该工具…

数据插值之朗格朗日插值(一)

目录 一、引言 二、代码实现 2.1 Lagrange插值求插值多项式&#xff1a; 代码解析&#xff1a; 1.vpa解释 2.ploy&#xff08;x&#xff09;解释: 3.conv&#xff08;&#xff09;解释 4.poly2sym()解释 2.2 Lagrange插值求新样本值和误差估计&#xff1a; 代码解析&…

【编译原理】LL(1)预测分析法

一、实验目的 LL(1)的含义&#xff1a;第一个L表明自顶向下分析是从左向右扫描输入串&#xff0c;第2个L表明分析过程中将使用最左推导&#xff0c;1表明只需向右看一个符号便可决定如何推导&#xff0c;即选择哪个产生式进行推导。 LL(1) 预测分析方法是确定的自顶向下的语…

2024年【N1叉车司机】免费试题及N1叉车司机模拟试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 N1叉车司机免费试题考前必练&#xff01;安全生产模拟考试一点通每个月更新N1叉车司机模拟试题题目及答案&#xff01;多做几遍&#xff0c;其实通过N1叉车司机模拟考试题库很简单。 1、【多选题】《中华人民共和国特…

第三讲 栈、队列和数组 (1)

文章目录 第三讲 栈、队列和数组3.1 栈3.1.1 出栈元素的不同排列与卡特兰数3.1.2 栈的顺序表实现3.1.3共享栈3.1.4 栈的链表实现3.1.5 栈的两种实现的优缺点3.1.6 c中的栈( s t a c k stack stack)容器适配器3.1.7 栈的应用:star:3.1.7.1 **栈在括号匹配中的应用**3.1.7.2 **栈…

m1系列芯片aarch64架构使用docker-compose安装rocketmq5.0以及运维控制台

之前看到 DockerHub 上有大佬制作了 m1 芯片, aarch64架构的 rocketmq 镜像, 所以就尝试的安装了下, 亲测可用: 一. docker-compose.yml 文件命令 volumes 挂载目录需要换成自己的目录 注意 depends_on 标签, broker 和 console 的 启动要晚于 namesrv, 因为 broker 需要注册…

MPLS LDP原理与配置

1.LDP基本概念 &#xff08;1&#xff09;LDP协议概述 &#xff08;2&#xff09;LDP会话、LDP邻接体、LDP对等体 &#xff08;3&#xff09;LSR ID 与LDP ID &#xff08;4&#xff09;LDP消息 ⦁ 按照消息的功能&#xff0c;LDP消息一共可以分为四大类型&#xff1a;发现…

JKI State Machine的特点与详细介绍

JKI State Machine是一种基于状态机的LabVIEW架构&#xff0c;由JKI公司开发。它广泛用于开发复杂的应用程序&#xff0c;提供了一种灵活且可扩展的结构&#xff0c;适用于多种任务的管理和执行。其设计目标是提高开发效率、代码可读性和可维护性。 2. 基本架构 JKI State Ma…

【算法题】520 钻石争霸赛 2024 全解析

都是自己写的代码&#xff0c;发现自己的问题是做题速度还是不够快 520-1 爱之恒久远 在 520 这个特殊的日子里&#xff0c;请你直接在屏幕上输出&#xff1a;Forever and always。 输入格式&#xff1a; 本题没有输入。 输出格式&#xff1a; 在一行中输出 Forever and always…