map与set容器常见操作详解(含示例代码及注意事项)

🎉个人名片:

🐼作者简介:一名乐于分享在学习道路上收获的大二在校生
🙈个人主页🎉:GOTXX
🐼个人WeChat:ILXOXVJE
🐼本文由GOTXX原创,首发CSDN🎉🎉🎉
🐵系列专栏:零基础学习C语言----- 数据结构的学习之路----C++的学习之路
🐓每日一句:如果没有特别幸运,那就请特别努力!🎉🎉🎉 ————————————————

文章目录

    • 文章简介:
    • 一.set的介绍
        • set文档介绍总结:
        • set的使用
          • set原型:
          • 构造函数
          • 插入操作
          • 删除操作
          • 寻找操作
          • lower_bound AND upper_bound
    • 二.关联式容器
    • 三.map的介绍
        • map文档介绍总结
        • map的使用
          • map原型:
          • 构造函数
          • 插入操作
          • 删除操作
          • 寻找操作
          • operator[ ]详解
    • 四.multiset与multimap

文章简介:

通过阅读这篇文章,可以全面了解C++中的map与set容器,掌握它们的基本用法和常见操作,从而在实际编程中更加灵活地运用这两个容器。

一.set的介绍

文档链接:link

set文档介绍总结:

1.set是按照一定次序存储元素的容器,在set中,元素的value也标识它(value就是key,类型为T),并且每个value必须是唯一的。
2.set中的元素不能在容器中修改(元素总是const),但是可以从容器中插入或删除它们。
3.在内部,set中的元素总是按照其内部比较对象(类型比较)所指示的特定严格强弱排序准则进行排序。
4.set容器通过key访问单个元素的速度通常比unordered_set容器慢,但它们允许根据顺序对子集进行直接迭代。
5.set在底层是用二叉搜索树(红黑树)实现的。

注意:

  1. 与map/multimap不同,map/multimap中存储的是真正的键值对<key, value>,set中只放value,但在底层实际存放的是由<value, value>构成的键值对。

  2. set中插入元素时,只需要插入value即可,不需要构造键值对。

  3. set中的元素不可以重复(因此可以使用set进行去重)。

  4. 使用set的迭代器遍历set中的元素,可以得到有序序列。

  5. set中的元素默认按照小于来比较。

  6. set中查找某个元素,时间复杂度为: l o g 2 n log_2 n log2n

  7. set中的底层使用二叉搜索树(红黑树)来实现。

set的使用
set原型:

在这里插入图片描述
第一个模板参数class T,T为存储的的数据类型;
第二个是控制比较逻辑的,默认是升序,改变逻辑为greater为降序;
第三个内存池,申请空间;

构造函数

在这里插入图片描述
常用构造
1.支持用容器的一个迭代器区间构造

2.支持用另一个set去构造

代码演示:

int main()
{vector<int> v = { 11,22,1,5,2,8,6,4,9 }; list<int> lt = { 11,22,1,5,2,8,6,4,9 };set<int> s(v.begin(), v.end());       //迭代器区间构造set<int> s2(lt.begin(), lt.end());    //迭代器区间构造set<int> s3(s2);                      //用s2去构造s3for (auto& e : s){cout << e << ' ';}cout << endl;for (auto& e : s2){cout << e << ' ';}cout << endl;for (auto& e : s3){cout << e << ' ';}return 0;
}
//运行结果:
1 2 4 5 6 8 9 11 22
1 2 4 5 6 8 9 11 22
1 2 4 5 6 8 9 11 22
插入操作

在这里插入图片描述
解析:

(1)直接插入一个val,如果set里面已经存在这个值,则返回当前的iterator,bool返回false;
如果set里面没有该val,则插入val,并返回新插入的val的iterator,bool返回true;
(2)在postition位置插入val,如果set里面没有该值,则插入,返回新插入的val的iterator;
否则返回已经存在的val的iterator;
(3)将一个迭代器区间的值插入,无返回值;

代码演示:

void settest2()
{vector<int> v = { 11,22,1,5,2,8,6,4,9 };set<int> s;set<int> s1;set<int> s2;s.insert(20);                      //直接插入一个vals1.insert(v.begin(), v.end());    //迭代器区间构造s2.insert(s2.begin(),4);          //在position位置插入一个valfor (auto& e : s){cout << e << ' ';}cout << endl;for (auto& e : s1){cout << e << ' ';}cout << endl;for (auto& e : s2){cout << e << ' ';}cout << endl;}//运行结果:
20
1 2 4 5 6 8 9 11 22
4
删除操作

在这里插入图片描述
解析:

(1)删除position位置元素
(2)删除set中所有val,并返回删除了多少个;(set没有重复元素,返回的是1 or 0,对于multiset来讲,返回的个数可以是多个,因为multiset允许数据重复)
(3)删除一个迭代器区间

代码演示

void settest3()
{vector<int> v = { 11,22,1,5,2,8,6,4,9 };set<int> s(v.begin(), v.end());    //v初始化sfor (auto& e : s){cout << e << ' ';}cout << endl;s.erase(--s.end());           //删除第一个元素,删除迭代器位置的元素for (auto& e : s)            //end()是最后一个元素的下一个元素,所以要--;{cout << e << ' ';}cout << endl;int ret = s.erase(11);       //删除11,set里有,应该返回1     cout << ret << endl;         //打印返回值int ret2 = s.erase(100);     //删除100,set里面没有,应该返回0cout << ret2 << endl;        //打印返回值for (auto& e : s){cout << e << ' ';}cout << endl;s.erase(s.begin(),s.end());    //删除迭代器区间的元素for (auto& e : s){cout << e << ' ';}cout << endl;}
//打印结果:
1 2 4 5 6 8 9 11 22
1 2 4 5 6 8 9 11
1
0
1 2 4 5 6 8 9
寻找操作

在这里插入图片描述
解析:

在set中寻找val,如果找到了返回该值的const迭代器,如果没有找到,则返回end();

代码演示:

void settest4()
{vector<int> v = { 11,22,1,5,2,8,6,4,9 };set<int> s(v.begin(), v.end()); for (auto& e : s){cout << e << ' ';}cout << endl;for (int i = 0; i < v.size(); i++)    //依次遍历v中元素{const auto& it = s.find(v[i]);    //找元素位置s.erase(it);                      //删除for (auto& e : s)                 //打印{cout << e << ' ';}cout << endl;}
}
//运行结果:
1 2 4 5 6 8 9 11 22
1 2 4 5 6 8 9 22
1 2 4 5 6 8 9
2 4 5 6 8 9
2 4 6 8 9
4 6 8 9
4 6 9
4 9
9
lower_bound AND upper_bound

在这里插入图片描述
在这里插入图片描述

解析:
lower_bound:

寻找val,如果存在该元素,则返回该位置的迭代器,如果不存在,则返回比val大的那一个元素的迭代器;

upper_bound:

寻找val,如果存在该元素,则返回比val大的那一个元素的迭代器,如果不存在,也返回比val大的那一个元素的迭代器;

代码演示:

void settest5()
{vector<int> v = { 11,22,1,5,2,8,6,4,9 };set<int> s(v.begin(), v.end());for (auto& e : s)                 {cout << e << ' ';}cout << endl;const auto& it = s.lower_bound(5);    //5存在  ,返回的是5的位置的迭代器cout << *it << endl;const auto& it1 = s.lower_bound(7);    //7不存在 ,返回的是比7大的呢一个元素的位置的迭代器cout << *it1 << endl;const auto& it2 = s.upper_bound(11);    //11存在 ,返回的是比11大的一个元素位置的迭代器cout << *it2 << endl;const auto& it3 = s.upper_bound(10);    //10不存在,返回的是比10大那一个元素位置的迭代器cout << *it3 << endl;}
//运行结果:
1 2 4 5 6 8 9 11 22
5
8
22
11

二.关联式容器

STL中的部分容器,比如:vector、list、deque、forward_list(C++11)等,这些容器统称为序列式容器,因为其底层为线性序列的数据结构,里面存储的是元素本身。
关联式容器也是用来存储数据的,与序列式容器不同的是,其里面存储的是<key, value>结构的键值对,在数据检索时比序列式容器效率更高。

键值对

用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量key和value,key代表键值,value表示与key对应的信息。比如:现在要建立一个英汉互译的字典,那该字典中必然有英文单词与其对应的中文含义,而且,英文单词与其中文含义是一一对应的关系,即通过该应该单词,在词典中就可以找到与其对应的中文含义。

三.map的介绍

map的文档链接:link

map文档介绍总结
  1. map是关联容器,它按照特定的**次序(按照key来比较)**存储由键值key和值value组合而成的元素。
  2. 在map中,键值key通常用于排序和惟一地标识元素,而值value中存储与此键值key关联的内容。键值key和值value的类型可能不同,并且在map的内部,key与value通过成员类型value_type绑定在一起,为其取别名称为pair: typedef pair<const key, T> value_type;
  3. 在内部,map中的元素总是按照键值key进行比较排序的。
  4. map中通过键值访问单个元素的速度通常比unordered_map容器慢,但map允许根据顺序对元素进行直接迭代(即对map中的元素进行迭代时,可以得到一个有序的序列)。
  5. map支持下标访问符,即在[ ]中放入key,就可以找到与key对应的value。
  6. map通常被实现为二叉搜索树(更准确的说:平衡二叉搜索树(红黑树))。
map的使用
map原型:

在这里插入图片描述

构造函数

在这里插入图片描述
解析:
常用的就是2与3

(2)用一个迭代器区间构造
(3)用另一个map去构造

代码演示

void maptest1()
{map<string, string> kv;kv["hello"] = "你好";kv["string"] = "字符串";kv["world"] = "世界";kv["apple"] = "苹果";kv["red"] = "红色";map<string, string>::iterator it = kv.begin();while (it != kv.end()){cout << it->first << ':' << it->second << ' ';++it;}cout << endl;map<string, string> kv2(kv.begin(), kv.end());      //迭代器区间构造map<string, string>::iterator it2 = kv2.begin();while (it2 != kv2.end()){cout << it2->first << ':' << it2->second << ' ';++it2;}cout << endl;  map<string, string> kv3(kv2);   //用另一个map去构造map<string, string>::iterator it3 = kv3.begin();while (it3 != kv3.end()){cout << it3->first << ':' << it3->second << ' ';++it3;}cout << endl;}
//运行结果:
apple:苹果 hello:你好 red:红色 string:字符串 world:世界
apple:苹果 hello:你好 red:红色 string:字符串 world:世界
apple:苹果 hello:你好 red:红色 string:字符串 world:世界
插入操作

在这里插入图片描述

解析:

(1)直接插入一个val,如果set里面已经存在这个值,则返回当前的iterator,bool返回false;
如果set里面没有该val,则插入val,并返回新插入的val的iterator,bool返回true;
(2)在postition位置插入val,如果set里面没有该值,则插入,返回新插入的val的iterator;
否则返回已经存在的val的iterator;
(3)将一个迭代器区间的值插入,无返回值;

代码演示

void maptest2()
{map<string, string> kv;kv["hello"] = "你好";kv["string"] = "字符串";map<string, string> kv2;kv2.insert(make_pair("yellow", "黄色"));   //直接插入kv2.insert(kv.begin(), kv.end());    //将kv迭代器区间的元素插入kv2.insert(kv2.begin(), make_pair("red", "红色"));   //在position位置插入一个元素map<string, string>::iterator it1 = kv2.begin();while (it1 != kv2.end()){cout << it1->first << ':' << it1->second << ' ';++it1;}cout << endl;
}
//运行结果:
hello:你好 red:红色 string:字符串 yellow:黄色
删除操作

在这里插入图片描述

解析:

(1)删除position位置元素
(2)删除set中所有k,并返回删除了多少个;(map没有重复元素,返回的是1 or 0,对于multiset来讲,返回的个数可以是多个,因为multimap允许数据重复)
(3)删除一个迭代器区间

void maptest3()
{map<string, string> kv;kv["hello"] = "你好";kv["string"] = "字符串";kv["world"] = "世界";kv["apple"] = "苹果";kv["red"] = "红色";map<string, string>::iterator it1 = kv.begin();while (it1 != kv.end()){cout << it1->first << ':' << it1->second << ' ';++it1;}cout << endl;kv.erase("hello");                      //删除hello元素it1 = kv.begin();while (it1 != kv.end()){cout << it1->first << ':' << it1->second << ' ';++it1;}cout << endl;kv.erase(kv.begin());                     //删除一个迭代器位置的元素it1 = kv.begin();while (it1 != kv.end()){cout << it1->first << ':' << it1->second << ' ';++it1;}cout << endl;kv.erase(kv.begin(), kv.end());            //删除一个迭代器区间  全部删除it1 = kv.begin();while (it1 != kv.end()){cout << it1->first << ':' << it1->second << ' ';++it1;}cout << endl;
}
//运行结果:
apple:苹果 hello:你好 red:红色 string:字符串 world:世界
apple:苹果 red:红色 string:字符串 world:世界
red:红色 string:字符串 world:世界
寻找操作

寻找操作与set类似,就不讲解了,这里重点详解operator[ ]的操作;

operator[ ]详解

在这里插入图片描述

解析:

operator[ ]调用的是insert函数类实现的(其中使用的是返回值为pair<iteraotr,bool> 的insert函数)

insert函数的功能(前面讲解过):
功能:直接插入一个val,如果set里面已经存在这个值,则返回当前的iterator,bool返回false;
如果set里面没有该val,则插入val,并返回新插入的val的iterator,bool返回true;

operator[ ]功能:
如果待插入元素(k)已经存在,则返回已经存在的这个元素的迭代器指向的pair里面第二个值的引用;
如果待插入元素不存在,则先调用insert函数插入一个k ,返回这个元素的迭代器的第二个值的引用;

代码演示

void maptest4()
{map<string, int> kv;string arr[] = { "hello","red","blue","hello","apple","blue" };for (auto& e : arr){kv[e]++;}auto it = kv.begin();while (it!=kv.end()){cout << it->first << '[' << it->second << ']' << endl;++it;}
}
//运行结果:
apple[1]
blue[2]
hello[2]
red[1]

四.multiset与multimap

multiset与set类似,只不过它允许val值可以重复;

注意:

  1. multiset中再底层中存储的是<value, value>的键值对
  2. mtltiset的插入接口中只需要插入即可
  3. 与set的区别是,multiset中的元素可以重复,set是中value是唯一的
  4. 使用迭代器对multiset中的元素进行遍历,可以得到有序的序列
  5. multiset中的元素不能修改
  6. 在multiset中找某个元素,时间复杂度为 O ( l o g 2 N ) O(log_2 N) O(log2N)
  7. multiset的作用:可以对元素进行排序

举个栗子:

void multisetTest()
{multiset<int> ms;vector<int> v = { 19,2,3,6,3,2,8,19,8,10,6, };for (auto& e : v){ms.insert(e);}for (auto& e : ms){cout << e << ' ';}}
//运行结果:
2 2 3 3 6 6 8 8 10 19 19

multimap与map类似,只不过它也是允许k值可以重复;

注意:

  1. multimap中的key是可以重复的;
  2. multimap中的元素默认将key按照小于来比较;
  3. multimap中没有重载operator[]操作;
  4. 使用时与map包含的头文件相同;

举个例子:

multimap

//multimap
void multismpapTest()
{multimap<string, int> kv;kv.insert(make_pair("apple", 1));kv.insert(make_pair("apple", 2));kv.insert(make_pair("apple", 3));kv.insert(make_pair("apple", 4));kv.insert(make_pair("apple", 5));auto it = kv.begin();while (it != kv.end()){cout << it->first << ':' << it->second << endl;++it;}
}//运行结果:
apple:1
apple:2
apple:3
apple:4
apple:5

map

//map
void multismpapTest()
{map<string, int> kv;kv.insert(make_pair("apple", 1));kv.insert(make_pair("apple", 2));kv.insert(make_pair("apple", 3));kv.insert(make_pair("apple", 4));kv.insert(make_pair("apple", 5));auto it = kv.begin();while (it != kv.end()){cout << it->first << ':' << it->second << endl;++it;}
}
//运行结果:
apple:1

本章完~

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

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

相关文章

LeetCode-热题100:73. 矩阵置零

题目描述 给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 示例 1&#xff1a; 输入&#xff1a; matrix [[1,1,1],[1,0,1],[1,1,1]] 输出&#xff1a; [[1,0,1],[0,0,0],[1,0,1]] 示例 2&…

企微侧边栏开发(内部应用内嵌H5)

一、背景 公司的业务需要用企业微信和客户进行沟通&#xff0c;而客户的个人信息基本都存储在内部CRM系统中&#xff0c;对于销售来说需要一边看企微&#xff0c;一边去内部CRM系统查询&#xff0c;比较麻烦&#xff0c;希望能在企微增加一个侧边栏展示客户的详细信息&#xf…

常见手撕项目C++

常见手撕项目C 设计模式单例模式饿汉模式懒汉模式 设计模式 单例模式 单例模式是一种常用的软件设计模式&#xff0c;其目的是确保一个类只有一个实例&#xff0c;并提供一个全局访问点来获取该实例。 优点&#xff1a; 资源控制&#xff1a;单例模式能够确保一个类只有一个实…

淘宝订单中的涉及红包检测、优惠券检测方案|工具|API

首先&#xff0c;检测订单红包的核心价值是什么&#xff1f; “红包的本质就是薅平台羊毛&#xff1a;不用怀疑&#xff0c;平台对于这种损害平台利益的行为肯定是最高等级的稽查”。那么&#xff0c;在日常运营中&#xff0c;需要尽可能过滤这类订单。 其次&#xff0c;如何使…

【数据结构 | 图论】如何用链式前向星存图(保姆级教程,详细图解+完整代码)

一、概述 链式前向星是一种用于存储图的数据结构&#xff0c;特别适合于存储稀疏图&#xff0c;它可以有效地存储图的边和节点信息&#xff0c;以及边的权重。 它的主要思想是将每个节点的所有出边存储在一起&#xff0c;通过数组的方式连接&#xff08;类似静态数组实现链表…

慧天【HTWATER】:水文水动力模型的革命性工具,城市内涝的精准解决方案

城市内涝水文水动力模型介绍 在城市排水防涝规划过程中&#xff0c;水文水动力耦合模型已经成为一种不可或缺的分析工具。在模型建立、城市内涝风险评估、排水系统性能诊断以及海绵城市规划等方面&#xff0c;内涝耦合模型提供了相应的模拟及分析工具&#xff1a; 1.1丰富的数…

前端学习<二>CSS基础——09-CSS案例讲解:博雅互动

前言 CSS已经学了一些基础内容了&#xff0c;我们来讲解一个小案例吧。以博雅互动的官网首页举例。 版心 首页的版心如下&#xff1a; 这里我们要普及一个概念&#xff0c;叫“版心”。版心是页面中主要内容所在的区域。 比如说&#xff0c;网站左上角的logo&#xff0c;设计…

Flutter 开发学习笔记(0):环境配置

文章目录 前言开发需求环境配置运行出现问题我运行也是解决了很久的问题镜像源设置为清华的镜像源&#xff08;不知道有没有影响&#xff09;使用JDK21&#xff0c;JDK版本不能低于JDK11手动下载flutter 对应的gradle 运行成功&#xff01; 前言 我最近一直在用Uniapp写代码&a…

vmware,linux,centos7,NAT模式下的网络配置

centos7的NAT网络配置 NAT模式说明虚拟机网络配置工具本机配置net8网络&#xff08;NAT的网域&#xff09;本机的IP配置(用于net8局域网内解析主机IP和域名对应关系使用)&#xff08;可选&#xff09;虚拟机内的网络配置虚拟机ping不通www.baidu.com的情况下虚拟机ping可以ping…

ARM64架构栈帧以及帧指针FP

文章目录 前言一、arm64架构寄存器简介1.1 异常等级1.2 通用寄存器1.3 ARM64架构ABI 二、ARM64架构函数调用标准2.1 AArch64过程调用标准简介2.2 通用寄存器中的参数 三、demo分析3.1 main函数3.2 funb3.3 funa 四、栈帧总结五、demo演示参考资料 前言 这篇文章描述了 x86_64架…

智过网:一建36岁好不好找工作?能干什么?

在职业发展的道路上&#xff0c;许多人在不同的年龄阶段都会面临不同的挑战和机遇。对于36岁这一年龄阶段的人来说&#xff0c;如果已经通过了国家一级建造师&#xff08;一建&#xff09;的考试&#xff0c;那么他们在找工作方面会有怎样的前景呢&#xff1f;又能从事哪些职业…

气象预测新篇章:Python人工智能的变革力量

Python是功能强大、免费、开源&#xff0c;实现面向对象的编程语言&#xff0c;在数据处理、科学计算、数学建模、数据挖掘和数据可视化方面具备优异的性能&#xff0c;这些优势使得Python在气象、海洋、地理、气候、水文和生态等地学领域的科研和工程项目中得到广泛应用。可以…

20.变量的使用方式和注意事项

文章目录 一、变量的用法二、变量的注意事项三、总结 一、变量的用法 代码示例 public static void main(String[] args) {//1.基本用法// 定义变量&#xff0c;再进行输出int a 10;System.out.println(a);// 10System.out.println(a);// 10//2.变量参与计算int b 30;int c …

代码随想录学习Day 21

回溯算法理论基础 回溯法又叫回溯搜索法。回溯是递归的副产品&#xff0c;有递归就会有回溯&#xff0c;回溯操作一般出现在递归函数的下面。回溯函数 递归函数。回溯法的本质是穷举。 回溯法解决的问题&#xff1a; 组合问题&#xff1a;N个数里面按一定规则找出k个数的集…

【超图 SuperMap3D】【基础API使用示例】51、超图SuperMap3D - 绘制圆|椭圆形面标注并将视角定位过去

前言 引擎下载地址&#xff1a;[添加链接描述](http://support.supermap.com.cn/DownloadCenter/DownloadPage.aspx?id2524) 绘制圆形或者椭圆形效果 核心代码 entity viewer.entities.add({// 圆中心点position: { x: -1405746.5243351874, y: 4988274.8462937465, z: 370…

小狐狸JSON-RPC:钱包连接,断开连接,监听地址改变

detect-metamask 创建连接&#xff0c;并监听钱包切换 一、连接钱包&#xff0c;切换地址&#xff08;监听地址切换&#xff09;&#xff0c;断开连接 使用npm安装 metamask/detect-provider在您的项目目录中&#xff1a; npm i metamask/detect-providerimport detectEthereu…

vue2的孙子传值给爷爷,爷爷传值给孙子

孙---->爷 在爷爷组件&#xff0c;给父亲组件绑定一个方法 定义一个方法用来接受传来的值 在父亲组件中 给孙子组件绑定v-on“$listeners” 在孙子组件 在特定掉件触发下&#xff0c;将值穿过去&#xff0c;注意&#xff1a;这里的this.$emit的名字要跟爷爷绑定的一…

R语言赋值符号<-、=、->、<<-、->>的使用与区别

R语言的赋值符号有&#xff1c;-、、-&#xff1e;、&#xff1c;&#xff1c;-、-&#xff1e;&#xff1e;六种&#xff0c;它们的使用与区别如下: <-’&#xff1a;最常用的赋值符号。它将右侧表达式的值赋给左侧的变量&#xff0c;像一个向左的箭头。例如&#xff0c;x …

【大数据运维】minio 常见shell操作

文章目录 1. 安装2. 入门操作3. 命令帮助 1. 安装 下载 https://dl.min.io/client/mc/release/linux-amd64/ 赋权与使用 cp mc /usr/bin && chmod x /usr/bin/mc ./mc --help 2. 入门操作 # 添加minio到mc mc config host add minio_alias_name endpoint_adress …

超市收银系统-亿发智能收银,引领线上线下一体化新零售管理

社交新零售的传播核心在于移动互联网。从信任关系的角度来看&#xff0c;移动互联网为用户之间搭建了沟通的桥梁&#xff0c;促进了人们之间更频繁的交流&#xff0c;从而建立了信任关系。从场景的角度来看&#xff0c;移动互联网使得用户之间的沟通更加多样化&#xff0c;包括…