C++进阶篇章:set与map(pair , multiset , multimap)

目录

1.关联式容器与序列式容器

2.pair(键值对)

3.set

构造函数

find函数

count函数:

insert函数

4.multiset

5.map

insert函数

operator[]


1.关联式容器与序列式容器

C++中关联式容器与序列式容器是两种不同的容器

   1.关联式容器

关联式容器:

  1. 关联式容器主要包括 std::set, std::map, std::multiset, std::multimap 等。
  2. 这些容器是基于键值对(<key, value>结构)的概念,通过键==(key)来唯一标识元素==。
  3. 关联式容器内部使用二叉搜索树(通常是红黑树)或类似的数据结构,以保持元素的有序性。
  4. 插入、删除、查找等操作的平均时间复杂度是 O(log n)。

序列式容器:

  1. 序列式容器包括 std::vector, std::list, std::deque, std::array 等。
  2. 这些容器是基于线性结构的,元素在容器中的位置是由插入的顺序决定的。
  3. 插入、删除、查找等操作的平均时间复杂度因容器类型而异,但在最差情况下,可能达到 O(n)。

2.pair(键值对)

C++中有一种数据结构,他能将两种不同的数据类型给强制的绑定,形成相连关系

定义:pair包含在<utility> 的头文件中 ,其中pair中有两个成员变量 , 一个是first , 另一个就是second 

STL库中pair的定义(没有具体实现swap,make_pair等函数)

template <class T1, class T2>
struct pair
{T1 first;T2 second;pair(T1 a = T1() , T2 b = T2() ) //构造函数: first(a), second(b){}pair(const T1& a, const T2& b) //拷贝构造: first(a), second(b){}
};

pair的构造函数

1.构造函数

具体代码实现请看上面

实例:

#include<iostream>
#include<vector>
#include<string>
#include<map>
#include<queue>
#include<utility>
using namespace std;
int main()
{pair<int, int> t(1, 1);pair<int, int> k;cout << t.first << " " << t.second << endl;cout << k.first << " " << k.second << endl;return 0;
}

2.拷贝构造函数

#include<iostream>
#include<vector>
#include<string>
#include<map>
#include<queue>
#include<utility>
using namespace std;
int main()
{pair<int, int> t(1, 1);// 构造函数pair<int, int> k = t;// 拷贝构造函数pair<int, int> s(t);// 拷贝构造函数cout << t.first << " " << t.second << endl;cout << k.first << " " << k.second << endl;cout << s.first << " " << s.second << endl;return 0;
}

3.make_pair函数(函数模版)

传入key , value 生成 pair , 并返回pair

#include<iostream>
#include<vector>
#include<string>
#include<map>
#include<queue>
#include<utility>
using namespace std;
int main()
{pair<string, string> t = { "abc" , "def" };t = make_pair<string,string>("afad", "fasd");cout << t.first << " " << t.second << endl;return 0;
}

3.set

  1. set是按照某一次序存储元素的
  2. set是key值模型,但也存在value(并且value = key ),set中key(value)值不能修改
  3. 底层使用红黑树实现的

构造函数

1.迭代器区间构造

2.拷贝构造

#include<iostream>
#include<vector>
#include<string>
#include<map>
#include<set>
#include<queue>
#include<utility>
using namespace std;
int main()
{vector<string> ret = { "a" , "b" , "c" };set<string>  ans(ret.begin(), ret.end());set<string> k = ans;for (auto& e : ans)cout << e << endl;return 0;
}

find函数

给定一个key,如果set中存在,返回该节点的迭代器,不存在,返回set.end()

#include<iostream>
#include<vector>
#include<string>
#include<map>
#include<set>
#include<queue>
#include<utility>
using namespace std;
int main()
{vector<string> ret = { "a" , "b" , "c" };set<string>  ans(ret.begin(), ret.end());auto it = ans.find("a");if (it != ans.end())cout << *it << endl;elsecout << "不存在" << endl;return 0;
}

count函数:

给定一个key值 ,如果set中存在,返回1 , 不存在,返回0(与find函数相似)

int main()
{vector<string> ret = { "a" , "b" , "c" };set<string>  ans(ret.begin(), ret.end());int i = ans.count("a");if (i)cout << i << endl;else cout << i << endl;return 0;
}

insert函数


声明:pair<iterator, bool> insert(const value_type& val);

插入元素到 set 中。


如果插入成功,返回一个迭代器指向插入的位置和 true。


如果元素已经存在,返回一个迭代器指向已存在的元素和 false。


返回一个 pair 对象,包含插入的迭代器和插入是否成功的标志。

int main()
{vector<string> ret = { "a" , "b" , "c" };set<string>  ans(ret.begin(), ret.end());ans.insert({ "d" });return 0;
}

  1. 删除一个迭代器所指向的节点
  2. 删除某一特定的值
  3. 删除某一迭代区间(左闭右开)
#include<iostream>
#include<vector>
#include<string>
#include<map>
#include<set>
#include<queue>
#include<utility>
using namespace std;
int main()
{set<string> ret = { {"ab"} , {"cd"} , {"ef"} };ret.erase("ab");// 删除某一特定的值for (auto& e : ret)cout << e << endl;cout << endl;ret.insert({ "ab" });ret.erase(ret.begin());// 删除某一迭代器for (auto& e : ret)cout << e << endl;cout << endl;ret.insert({ "ab" });ret.insert({ "tt" });auto it = ret.find("tt");ret.erase(ret.begin(), it);for (auto& e : ret)cout << e << endl;return 0;
}

4.multiset

  1. multiset是按照特定顺序存储元素的容器,其中元素是可以重复的。
  2. 在multiset中,元素的value也会识别它(因为multiset中本身存储的就是<value, value>组成的键值对,因此value本身就是key,key就是value,类型为T). multiset元素的值不能在容器中进行修改(因为元素总是const的),但可以从容器中插入或删除。
  3. 在内部,multiset中的元素总是按照其内部比较规则(类型比较)所指示的特定严格弱排序准则进行排序。
  4. multiset容器通过key访问单个元素的速度通常比unordered_multiset容器慢,但当使用迭代器遍历时会得到一个有序序列。
  5. multiset底层结构为二叉搜索树(红黑树)

注意:

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

multiset 是 C++ 标准库中的关联式容器之一,属于有序容器。与 set 不同的是,multiset 允许键值重复,即可以包含相同键值的多个元素。

允许重复键值: multiset 允许容器中存在相同的键值,因此可以包含多个相同键值的元素。

有序性: 与 set 类似,multiset 也维护元素的有序性,根据键值进行排序。

当需要允许键值重复,并且希望保持元素有序时,可以选择使用 multiset。

#include<iostream>
#include<vector>
#include<string>
#include<map>
#include<set>
#include<queue>
#include<utility>
using namespace std;
int main()
{vector<int> k = { 2,1,5,6,7,3,1,1,1,90 };multiset<int> ret(k.begin(), k.end());for (auto& e : ret)cout << e << " ";cout << endl;return 0;
}

5.map

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

5.1map 模板参数说明

  1. key: 键值对中key的类型
  2. T: 键值对中value的类型
  3. Compare: 比较器的类型,map中的元素是按照key来比较的,缺省情况下按照小于来比较,一般情况下(内置类型元素)该参数不需要传递,如果无法比较时(自定义类型),需要用户自己显式传递比较规则(一般情况下按照函数指针或者仿函数来传递)
  4. Alloc:通过空间配置器来申请底层空间,不需要用户传递,除非用户不想使用标准库提供的空间配置器

构造函数

1.迭代器区间构造

2.拷贝构造

insert函数

void test()
{map<int,int> ret;ret.insert({1,1});ret.insert(make_pair(1,1));auto tmp = make_pair(1,1);ret.insert(tmp);
}

operator[]

返回的是关于value的引用

1.读取元素:当使用 [] 运算符时

  • 如果指定的键存在于 map 中,则返回与该键关联的值
  • 如果不存在,则会插入一个新的键值对,键为指定的键,值为默认构造的对应值类型的默认值,并返回该默认值的引用

2.插入元素:当使用 [] 运算符向 map 中插入元素时

  • 如果指定的键不存在,则会创建一个新的键值对,键为指定的键,值为指定的值,并返回该值的引用
  • 如果键已经存在,则直接返回对应的值的引用。
#include<iostream>
#include<map>
using namespace std;
int main()
{map<int, int> ret;vector<int> ans = { 1, 2, 3, 4, 5,6 ,6,7, };for (auto& e : ans){ret[e]++;// 插入pair}for (auto& e : ret){cout << e.first << " " << e.second << endl;}ret[1] = 10; // 修改pairreturn 0;
}

erase

第一种:删除 key 为某一个值的pair

#include<iostream>
#include<map>
using namespace std;
int main()
{map<int, int> ret;vector<int> ans = { 1, 2, 3, 4, 5,6 ,6,7, };for (auto& e : ans){ret[e]++;}for (auto& e : ret){cout << e.first << " " << e.second << endl;}ret.erase(1);cout << endl;for (auto& e : ret){cout << e.first << " " << e.second << endl;}return 0;
}

第二种:删除某一迭代区间(左闭右开)


#include<iostream>
#include<map>
using namespace std;
int main()
{map<int, int> ret;vector<int> ans = { 1, 2, 3, 4, 5,6 ,6,7, };for (auto& e : ans){ret[e]++;}for (auto& e : ret){cout << e.first << " " << e.second << endl;}auto p1 = ret.find(3);auto p2 = ret.find(6);cout << endl;ret.erase(p1, p2);for (auto& e : ret){cout << e.first << " " << e.second << endl;}return 0;
}

6.multimap

multimap的基本性质

  • multimap容器是和map容器相似的关联式容器,所谓“相似”,是指multimap容器具有和map容器相同的特性,即multimap容器也存储pair<const K, T>类型的键值对(其中K表示键的类型,T表示值的类型),其中各个键值对的键的值不能被修改;并且,该容器也会自行根据键的大小对所存储的所有键值对做排序操作。
  • multimap容器和map容器的区别在于,multimap容器中可以同时存储多个键相同的键值对。
  • multimap容器提供的成员方法,map容器都有提供,并且它们的用法是相同的。详细的用法请参照map的用法及实例详解。本文只是给出了所有在multimap中的成员函数及其实现功能,具体的实例及代码请参照map容器。
  • 实现multimap容器的类模板也定义在<map>头文件,并位于std命名空间中,故使用multimap容器前,应该引入头文件:#include<map>

构造函数

创建空的multimap

multimap<int,int> ret;

创建multimap并初始化(注意用{})

multimap<int, int> ret{ { 1,1 }, { 2,3 }, { 5,6 } };

拷贝构造

multimap<int,int> ans(ret);

迭代区间构造


#include<iostream>
#include<map>
#include<climits>
using namespace std;
int main()
{multimap<int, int> ret{ { 1,1 }, { 2,3 }, { 5,6 } };multimap<int, int> ans(++ret.begin(),ret.end());for (auto& e : ans)cout << e.first << " " << e.second << endl;return 0;
}

常见成员函数和使用方法:

注意multimap并没有重载operator[]

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

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

相关文章

GAMIT目录配置

1打开home&#xff0c;显示隐藏文件&#xff0c;CTRH 2修改目录 #set gamitpath gamitpath/opt/gamit10.7 export PATH$PATH:${gamitpath}/com/:${gamitpath}/gamit/bin:${gamitpath}/kf/bin HELP_DIR${gamitpath}/help export HELP_DIR #set GMT path gmtpath/usr/lib/gmt P…

力扣--双指针15.三数之和

详细思路 排序数组&#xff1a;首先对数组 nums 进行排序&#xff0c;目的是为了方便后续使用双指针查找和避免重复结果。遍历数组&#xff1a;使用一个 for 循环从头遍历到倒数第三个元素。i 表示当前固定的元素。 跳过重复元素&#xff1a;如果当前元素 nums[i] 与前一个元素…

SpringBoot项目实现自定义注解方式的接口限流

一&#xff0c;实现原理 该限流方式使用的是令牌桶算法&#xff0c;令牌桶算法是基于漏桶算法的一种改进&#xff0c;主要在于令牌桶算法能够在限制服务调用的平均速率的同时&#xff0c;还能够允许一定程度内的突发调用。 系统以固定的速率向桶中添加令牌当有请求到来时&#…

软设之快速排序

快速排序是冒泡排序的改进算法 它采用的是分治法&#xff0c;基本思想是把原问题分解为若干规模更小但结构与原问题相似的子问题&#xff0c;通过递归解决这些子问题&#xff0c;然后将这些子问题的解组合成原问题的解。 它的步骤是 1.在待排序的n个记录中任取一个记录&…

张大哥笔记:你卖什么,就反着来卖

普通人打工的一生&#xff0c;就是努力工作&#xff0c;买房&#xff0c;买车&#xff0c;送孩子上好的学校&#xff0c;为了孩子不要输在起跑线上&#xff0c;拼命报各种补习班等&#xff0c;这些都是普通人认为的主流价值观文化&#xff0c;也造就了一批批的赚钱机器&#xf…

带DSP音效处理D类数字功放TAS5805M中文资料

国产替代D类数字功放中文资料访问下方链接 ACM8628 241W立体声182W单通道数字功放中文寄存器表 内置DSP多种音频处理效果ACM8628M-241W立体声或182W单通道数字功放 1 特性 具有增强处理能力和低功率损耗的 TAS5805M 23W、无电感器、数字输入、立体声、闭环 D 类音频放大器 …

华为设备配置静态路由和默认路由

华为设备配置静态路由和默认路由 理论部分知识&#xff1a; 路由分为两个大类&#xff1a;静态路由-----动态路由 静态路由&#xff1a;手工指定&#xff0c;适用于小规模的网络应用场景&#xff0c;如果网络规模变大&#xff0c;这样的方式非常不适合而且容易出错。 语法&…

java单元测试如何断言异常

​ 在junit单元测试中&#xff0c;我们可以使用 org.junit.Assert.assertThrows 包下的 assertThrows() 方法 这个方法返回了一个泛型的异常 public static <T extends Throwable> assertThrows(Class<T> expectedType, Executable executable)​ 假设我们有以下…

Java之IO流

一、引言 &#xff08;1&#xff09;解释&#xff1a; i&#xff1a;input &#xff08;输入&#xff09; o&#xff1a;output &#xff08;输出&#xff09; &#xff08;2&#xff09;图解 注意&#xff1a; 1、Xxx 这个程序一旦在桌面关闭掉了&#xff0c;也就是运行完…

动态路由OSPF单区域和多区域配置实验

动态路由OSPF的配置 OSPF分类两种情况&#xff1a;单区域 多区域路由 OSPF单区域路由配置 OSPF&#xff1a;开放最短路径优先的路由协议。属于大型动态路由协议&#xff0c;适用于中大型的园区网。 网络拓扑&#xff1a; 配置步骤&#xff1a; 1.完成基本配置&#xff08;略&…

能耗监测系统在上海交通大学闵行校区理科实验楼群的设计与应用

引言 建筑能耗系统&#xff0c;除了基本的电力参数监测、配电系统的运行状况&#xff0c;更加关注能耗的去向。除了常规的园区楼层出线电能计量&#xff0c;还会涉及水&#xff0c;气等能耗计量。 针对上海交通大学闵行校区理科实验楼群能耗监测系统的具体要求&#xff0c;以…

android-AP6212配置

一、调试背景 硬件平台a33 系统android wifi:ap6212a 从内核日志看到模块能加载识别到fw_bcm43438a1.bin ,但是nvram加载的配置是nvram_ap6212.txt&#xff0c;虽然能正常工作&#xff0c;但是对比了一下nvram_ap6212.txt 和nvram_ap6212a.txt还是有差异的 内核日志&#xff1…

依赖管理包介绍

文章目录 1. 概念介绍2. 思路与方法2.1 实现思路2.2 相关组件 3. 示例代码4. 内容总结 我们在上一章回中介绍了"使用get进行依赖管理"相关的内容&#xff0c;本章回中将介绍如何使用get进行状态管理一.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 …

C语言:如何在微软VS环境下使用C库?

技术答疑流程 扫描二维码&#xff0c;添加个人微信&#xff1b;支付一半费用&#xff0c;获取答案&#xff1b;如果满意&#xff0c;则支付另一半费用&#xff1b; 知识点费用&#xff1a;10元 项目费用&#xff1a;如果有项目任务外包需求&#xff0c;可以微信私聊

Typescript高级: 深入理解ConstructorParameters类型及借助infer构建带参数的工厂实例方法

概述 在TypeScript中&#xff0c;利用泛型和类型推断&#xff0c;我们可以编写出既灵活又安全的代码特别是在处理类和其实例化过程中&#xff0c;这些特性显得尤为重要我们着重关注构造函数参数&#xff08;constructor parameters&#xff09;的类型处理以及如何利用泛型工厂…

IP路由策略1

控制层面:路由协议传递路由信息的流量--对应的方向 数据层面:设备间具体访问时请求的流量--对应方向 控制层面方向与数据层面方向一定相反 在控制层面流量进或出的接口上&#xff0c;抓取流量后&#xff0c;修改其中参数或删除该信息&#xff0c;最终起到影响路由器路由表的生…

「Django秘境探险:揭开Web开发的神秘面纱」

大家好&#xff0c;我是阿佑&#xff0c;今天将和大家一块学习到如何利用Django框架的高级特性&#xff0c;构建出既快速又安全的Web应用。我们将一起破解Django的内部机制&#xff0c;掌握从数据模型到模板设计的每一个环节。准备好了吗&#xff1f;Let’s go &#xff01; 文…

“手撕”链表的九道OJ习题

目录 1. 第一题 2. 第二题 3. 第三题 4. 第四题 5. 第五题 6. 第六题 7. 第七题 8. 第八题 9. 第九题 1. 第一题 删除链表中等于给定值 val 的所有节点。OJ链接 思路如下&#xff1a; 相当于链表的removeAll();制定prev和cur&#xff0c;prev记录前一个节点&#xff…

MySQL学习——行分类及日期计算

1 行分类 你可能已经在前面的例子中注意到&#xff0c;结果行的显示没有特定的顺序。当结果行以某种有意义的方式进行排序时&#xff0c;检查查询输出通常会更容易。要对结果进行排序&#xff0c;请使用ORDER BY子句。 以下是按日期排序的动物生日&#xff1a; mysql> SE…