Set和Map

一、Set的介绍

1.1、Set相关文档介绍

cplusplus.com/reference/set/set/?kw=set 

1. set是按照一定次序存储元素的容器
2. 在set中,元素的value也标识它(value就是key,类型为T),并且每个value必须是唯一的。
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中查找某个元素,时间复杂度为:log2 
7. set中的元素不允许修改
8. set中的底层使用二叉搜索树(红黑树)来实现

1.2、Set的使用

既然set是容器,那他也可以像前几个一样被构造。头文件#include<set>

1.空构造和拷贝构造
        set<int> s1;
        set<int> s2(s1);
2.迭代器构造
        string s3("I love C++");
        set<char> s4(s.begin(), s.end());
3.大于比较
        set的底层是搜素二叉树,默认是小于排序(升序),也可是调成大于排序(降序)。

        set<int, greater<int>> s5;

迭代器接口:

容量接口:

修改接口:

这里我们对Set进行一些测试:

#include<iostream>
#include<set>
using namespace std;void test1()
{set<int> s1;s1.insert(1);   //插入操作s1.insert(3);s1.insert(5);s1.insert(7);s1.insert(4);s1.insert(4);s1.insert(5);s1.insert(1);set<int> s2(s1);set<int>::iterator it = s1.begin();for (auto e : s1){cout << e << " ";   //  1 3 4 5 7,是升序排列,别搞错了}cout << endl;set<int>::iterator pos1 = find(s1.begin(), s1.end(), 5);set<int>::iterator pos2 = s1.find(7);   //set自带的查找函数if (it != s1.end()){s1.erase(pos1);   //删除5s1.erase(pos2);s1.insert(10);s1.insert(20);}while (it != s1.end()){cout << *it << " ";    //1 3 4 10 20*it++;}cout << endl;//删除指定区间set<int>::iterator ret = s2.find(5);s2.erase(s2.begin(), ret);for (auto e : s2){cout << e << " ";   //5 7}cout << endl;//寻找是否有val,找到返回1if (s2.count(5)) // s2中有5就返回1,进入循环{cout << "s2中有5:" << endl;  //s2中有5}cout << s2.empty() << endl;  // 判空cout << s1.size() << endl;   //s1的个数是5cout << s2.size() << endl;   //s2的个数是2
}int main()
{test1();
}

二、multiset 的介绍

2.1、multiset相关文档介绍

cplusplus.com/reference/set/multiset/?kw=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(log2)
7. multiset的作用:可以对元素进行排序

2.2、multiset的使用

 multiset的count和erase跟set相比有很大区别:

1、set.count(val)是如果找到val就返回1;因为multiset的数可以重复,multiset.count(val)找到val后返回multiset中有几个val。
2、set.erase(val)是找到要删除的val后,返回1;multiset.erase(val)找到要删除的val后返回val有几个,并且全删val。

这里我们对multiset进行一些测试:

void test2()
{multiset<int> multiset;multiset.insert(4);multiset.insert(5);multiset.insert(2);multiset.insert(1);multiset.insert(1);multiset.insert(3);multiset.insert(3);multiset.insert(3);for (auto e : multiset){cout << e << " ";   }cout << endl;set<int> set(multiset.begin(), multiset.end());cout << multiset.erase(1) << endl;//2 返回删除的1的个数for (auto e : multiset){cout << e << " ";  //2 3 3 3 4 5}cout << endl;cout << set.erase(4) << endl;//1 返回一个bool值,存在删除的值返回1for (auto e : multiset){cout << e << " ";  //2 3 3 3 4 5}cout << endl;auto pos1 = multiset.find(3); //返回中序的第一个3的迭代器while (pos1 != multiset.end()){cout << *pos1 << " ";//3 3 3 4 5pos1++;}
}

三、Map的介绍

3.1、Map相关文档介绍

cplusplus.com/reference/map/map/?kw=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通常被实现为二叉搜索树(更准确的说:平衡二叉搜索树(红黑树 ))

3.2、Map的使用

#include<iostream>
#include<map>
using namespace std;int main()
{map<string, int> m;//创建一个map对象m//向m中插入pairmap<string, int> m1(m.begin(), m.end);//用m的区间构造m1map<string, int> m2(m1);//用m1拷贝构造m2return 0;
}
key: 键值对中key的类型
T: 键值对中value的类型
Compare: 比较器的类型,map中的元素是按照key来比较的,缺省情况下按照小于来比
较,一般情况下(内置类型元素)该参数不需要传递,如果无法比较时(自定义类型),需要用户
自己显式传递比较规则(一般情况下按照函数指针或者仿函数来传递)
Alloc:通过空间配置器来申请底层空间,不需要用户传递,除非用户不想使用标准库提供的
空间配置器
注意:在使用map时,需要包含头文件#include<map>
map的迭代器
map的容量与元素访问
        
注意:在元素访问时,有一个与operator[ ]类似的操作at()(该函数不常用)函数,都是通过
key找到与key对应的value然后返回其引用,不同的是:当key不存在时,operator[ ]用默认
value与key构造键值对然后插入,返回该默认value,at()函数直接抛异常。
map中元素的修改
map的key不允许被修改。
map中元素的查找
map可以用[ ]进行访问(不是下标访问,一定要注意)
mapped_type& operator[] (const key_type& k);

具体实现如下:

mapped_type& operator[] (const key_type& k)
{return (*((this->insert(make_pair(k, mapped_type()))).first)).second;
}

这个如果不好理解的话,看一下下面这个:

mapped_type& operator[] (const key_type& k)
{//1、调用insert返回迭代器区间pair<iterator, bool> ret = insert(make_pair(k, mapped_type()));//2、利用ret调用value值return ret.first->second;//return (*(ret.first)).second;
}
  • 首先调用insert函数插入键值对返回迭代器ret
  • 通过返回的迭代器ret调用元素值value。

在这里我们又分两种情况去处理:

1、如果k在map对象中,则插入失败,返回的bool类型为false,返回的迭代器为k所在结点的迭代器,而迭代器解引用*(ret.first)获得的就是pair,最后再通过pair访问到value值,整体可优化成ret.first->second,这里返回引用的好处为查找k对应v,修改k对应v。


2、如果k不在map对象中,则插入成功,返回的bool类型为true,返回的迭代器为新插入的k所在结点的迭代器位置,接着调用ret.first获得pair的迭代器,再通过->second获得value,这里返回引用的好处为插入和修改。

对Map的测试:
void test_map1()
{map<string, string> dict;//dict.insert(pair<string, string>("sort", "排序"));dict.insert(make_pair("sort", "排序"));dict.insert(make_pair("string", "字符串"));dict.insert(make_pair("count", "计数"));//map<string, string>::iterator dit = dict.begin();auto dit = dict.begin();while (dit != dict.end()){cout << (*dit).first << ":" << (*dit).second << endl;++dit;}cout << endl;
}void test_map2()
{map<string, string> dict;//dict.insert(pair<string, string>("sort", "排序"));dict.insert(make_pair("sort", "排序"));dict.insert(make_pair("string", "字符串"));dict.insert(make_pair("count", "计数"));dict.insert(make_pair("string", "(字符串)")); // 插入失败dict["left"];			// 插入dict["right"] = "右边"; // 插入+修改dict["string"] = "(字符串)"; // 修改cout << dict["string"] << endl; // 查找cout << dict["string"] << endl; // 查找//map<string, string>::iterator dit = dict.begin();auto dit = dict.begin();while (dit != dict.end()){//cout << (*dit).first << ":" << (*dit).second << endl;cout << dit->first << ":" << dit->second << endl;++dit;}cout << endl;
}void test_map3()
{string arr[] = { "西瓜", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉", "梨" };map<string, int> countMap;//for (auto& e : arr)//{//	auto ret = countMap.find(e);//	if (ret == countMap.end())//	{//		countMap.insert(make_pair(e, 1));//	}//	else//	{//		ret->second++;//	}//}for (auto& e : arr){countMap[e]++;}for (auto& kv : countMap){cout << kv.first << ":" << kv.second << endl;}
}//V& operator[](const K& key)
//{
//	pair<iterator, bool> ret = insert(make_pair(key, V()));
//	return ret.first->second;
//}int main()
{test_map1();test_map2();test_map3();return 0;
}
【总结】
1. map中的的元素是键值对
2. map中的key是唯一的,并且不能修改
3. 默认按照小于的方式对key进行比较
4. map中的元素如果用迭代器去遍历,可以得到一个有序的序列
5. map的底层为平衡搜索树(红黑树),查找效率比较高O(log2)
6. 支持[]操作符,operator[]中实际进行插入查找。

四、multiset的介绍

4.1、multiset相关文档介绍

1. Multimaps是关联式容器,它按照特定的顺序,存储由key和value映射成的键值对<key,
value>,其中多个键值对之间的key是可以重复的。
2. 在multimap中,通常按照key排序和惟一地标识元素,而映射的value存储与key关联的内
容。key和value的类型可能不同,通过multimap内部的成员类型value_type组合在一起,
value_type是组合key和value的键值对: typedef pair<const Key, T> value_type;
3. 在内部,multimap中的元素总是通过其内部比较对象,按照指定的特定严格弱排序标准对
key进行排序的。
4. multimap通过key访问单个元素的速度通常比unordered_multimap容器慢,但是使用迭代
器直接遍历multimap中的元素可以得到关于key有序的序列。
5. multimap在底层用二叉搜索树(红黑树)来实现。
注意: multimap和map的唯一不同就是:map中的key是唯一的,而multimap中key是可以
重复的

4.2、multimap的使用

1、map中的valuevalue是唯一的,不允许重复。multimap可以。

2、multimap中没有[ ]。因为它的key和value是一对多的关系,比如上面的苹果,那key是苹果,但是苹果出现了好几次,每一个都有一个value,那他到底返回哪一个呢?为啥map能返回呢,因为在map中每一个key(苹果)都对应一个自己的value,所以每次返回一个value.但是multimap是一个key有好几个value.

multimap测试:
void test7()
{multimap<string, string> mlp1;mlp1.insert(make_pair("one", "一"));mlp1.insert(make_pair("two", "二"));mlp1.insert(make_pair("three", "三"));mlp1.insert(make_pair("four", "四"));mlp1.insert(make_pair("four", "四"));mlp1.insert(make_pair("spring", "五"));mlp1.insert(make_pair("spring", "五"));for (auto e : mlp1){cout << e.first << ":" << e.second << endl;}
}
int main()
{test7();
}

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

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

相关文章

时空序列问题的本质和底层逻辑

本质&#xff1a;Still need to polish this. 底层逻辑&#xff1a;Still need to polish this.See you pretty soon. Reference 【时空序列预测】什么是时空序列问题&#xff1f;这类问题主要应用了哪些模型&#xff1f;主要应用在哪些领域&#xff1f;_mb62b92582e5a0a的技…

【算法刷题】Day28

文章目录 1. 买卖股票的最佳时机 III题干&#xff1a;算法原理&#xff1a;1. 状态表示&#xff1a;2. 状态转移方程3. 初始化4. 填表顺序5. 返回值 代码&#xff1a; 2. Z 字形变换题干&#xff1a;算法原理&#xff1a;1. 模拟2. 找规律 代码&#xff1a; 1. 买卖股票的最佳时…

我是如何从计算机小白成长为技术专家的(上)?

作为一名程序员&#xff0c;我想大家接触最多的是计算机吧&#xff0c;但是一个从没有接触过计算机的小白&#xff0c;又是如何走上程序员的道路的呢。 农村的孩子&#xff0c;早当家 作为农村出身的孩子&#xff0c;且家里条件也不是非常的好&#xff0c;在我那个年代&#…

Linux网络配置与抓包工具介绍

目录 一、配置命令 1. ifconfig 1.1 概述信息解析 1.2 常用格式 2. ip 2.1 ip link 数据链路层 2.2 ip addr 网络层 2.3 路由 3. hostname 3.1 临时修改主机名 3.2 永久修改主机名 4. route 5. netstat 6. ss 7. ping 8. traceroute 9. nslookup 10. 永久修…

springcloud Config配置中心

简介 服务意味着要将单体应用中的业务拆分成一个个子服务&#xff0c;每个服务的粒度相对较小&#xff0c;因此系统中会出现大量的服务。由于每个服务都需要必要的配置信息才能运行&#xff0c;所以一套集中式的、动态的配置管理设施是必不可少的。 SpringCloud提供了ConfigS…

Android SDK环境搭建

一、Android SDK简介 SDK&#xff1a;&#xff08;software development kit&#xff09;软件开发工具包。被软件开发工程师用于为特定的软件包、软件框架、硬件平台、操作系统等建立应用软件的开发工具的集合。 因此&#xff0c;Android SDK 指的是Android专属的软件…

【Java集合篇】HashMap的remove方法是如何实现的?

HashMap的remove方法是如何实现的 ✔️典型解析✔️拓展知识仓✔️HashMap的remove方法的注意事项✔️HashMap的remove方法的参数类型✔️ 删除键和值的参数类型有什么区别✔️删除键值对的场景是什么 ✔️HashMap remove方法是阻塞队列的吗✔️HashMap remove方法是线程安全的…

如何使用web文件管理器Net2FTP搭建个人网盘

文章目录 1.前言2. Net2FTP网站搭建2.1. Net2FTP下载和安装2.2. Net2FTP网页测试 3. cpolar内网穿透3.1.Cpolar云端设置3.2.Cpolar本地设置 4.公网访问测试5.结语 1.前言 文件传输可以说是互联网最主要的应用之一&#xff0c;特别是智能设备的大面积使用&#xff0c;无论是个人…

Linux 常用指令汇总

Linux 常用指令汇总 文章目录 Linux 常用指令汇总[toc]前言一、文件目录指令pwd 指令ls 指令cd 指令mkdir 指令rmdir 指令tree 指令cp 指令rm 指令mv 指令cat 指令more 指令less 指令head 指令tail 指令echo 指令> 指令>> 指令 二、时间日期指令date 指令cal 指令 三、…

Mars3D与mars3d-cesium版本间兼容造成3dtiles和gltf数据处理相关记录

说明&#xff1a; 1.在引入Mars3D SDK后正常可以在F12打印的信息中可以看到Mars3D和Cesium版本信息。 2.在项目的package.json文件中同样可以看到安装后的版本号。 Mars3D对Cesium版本对应关系&#xff1a; 1.正常情况下mars3d依赖的cesium均是最新版本&#xff0c;并且对cesi…

53K star! 平替TeamViewer,试试这个开源神器

还记得以前工作上遇到困难&#xff0c;会申请开发大神远程帮忙&#xff0c;那时候用都是TeamViewer&#xff0c;但是随着TeamViewer的收费&#xff0c;这些都已成为过往。 今天我们推荐的开源项目就是让你可以轻松平替TeamViewer&#xff0c;一款远程桌面神器&#xff0c;本项…

Antd使用table同时使用scroll和fixed定位,滑动导致左右高度不统一

今天使用组件里Table时候&#xff0c;遇到一个业务场景就是在有scroll控制滚动条的同时&#xff0c;固定部分列&#xff0c;就出现的如题的bug 问题&#xff1a;无法对齐 代码&#xff1a; <TabledataSource{data}scroll{{ y: calc(100vh - 275px), x: 1200px }}columns{t…

智能合约介绍

莫道儒冠误此生&#xff0c;从来诗书不负人 目录 一、什么是区块链智能合约? 二、智能合约的发展背景 三、智能合约的优势 四、智能合约的劣势 五、一些关于智能合约的应用 总结 一、什么是区块链智能合约? 智能合约&#xff0c;是一段写在区块链上的代码&#xff0c;一…

Simpy简介:python仿真模拟库-03/5

一、说明 在过去的两篇文章中&#xff0c;我们了解了 simpy 的基础知识、声明变量和处理表达式。值得注意的例子包括评估导数和积分。现在&#xff0c;让我们继续使用函数。 二、SymPy — 函数类 SymPy 包包含 sympy.core.function 模块中的 Function 类。该类作为各种数学函数…

构建labelstudio镜像的时候,报错node:18,如何解决

解决方案&#xff1a; vi Dockerfile # syntaxdocker/dockerfile:1.3 FROM --platformlinux/amd64 node:18.16-bullseye-slim AS frontend-builder18改成 18.16-bullseye-slim

【漏洞复现】锐捷EG易网关login.php命令注入漏洞

Nx01 产品简介 锐捷EG易网关是一款综合网关&#xff0c;由锐捷网络完全自主研发。它集成了先进的软硬件体系架构&#xff0c;配备了DPI深入分析引擎、行为分析/管理引擎&#xff0c;可以在保证网络出口高效转发的条件下&#xff0c;提供专业的流控功能、出色的URL过滤以及本地化…

【2024系统架构设计】 系统架构设计师第二版-通信系统架构设计理论与实践

目录 一 通信系统网络架构 二 网络构建的关键技术 三 网络构建和设计方法 四 案例分析 注:本节内容可作为知识储备,做一个基本的了解即可。

Linux-命名管道

文章目录 前言一、命名管道接口函数介绍二、使用步骤 前言 上章内容&#xff0c;我们介绍与使用了管道。上章内容所讲的&#xff0c;是通过pipe接口函数让操作系统给我们申请匿名管道进行进程间通信。 并且这种进程间通信一般只适用于父子进程之间&#xff0c;那么对于两个没有…

原来这些小众知识库软件这么好用,挖到宝了

在企业管理中&#xff0c;知识库的作用越来越被重视。它不仅可以提高工作流程的效率&#xff0c;还可以最大限度地利用企业中的知识资源。然而&#xff0c;在众多的知识库工具中选择一款合适的并非易事。不用担心&#xff0c;今天我要为大家揭晓一些小众却非常好用的知识库软件…

微信小程序实战-02翻页时钟-2

微信小程序实战系列 《微信小程序实战-01翻页时钟-1》 文章目录 微信小程序实战系列前言计时功能实现clock.wxmlclock.wxssclock.js 运行效果总结 前言 接着《微信小程序实战-01翻页时钟-1》&#xff0c;继续完成“6个页面的静态渲染和计时”功能。 计时功能实现 clock.wxm…