【C++】set和map

set和map

  • 1. 预备知识
  • 2. set
    • 2.1 set的概念
    • 2.2 set的常见接口
  • 3. multiset
  • 4. map
    • 4.1 map的概念
    • 4.2 map的常见接口
  • 5. multimap
  • 6. 练习

1. 预备知识

  1. set和map是关联式容器,里面存储的不是元素本身,存储的是<key,value>结构的键值对,比vector、list、deque这些底层为线性序列的序列式容器,在数据检索时效率更高。
  2. 关联性容器有两种不同的结构:树形结构和哈希结构。set和map的底层结构是树形结构。使用平衡搜索树(即红黑树)作为底层结构,容器中的元素是一个有序的序列
  3. 键值对一般只包含两个成员变量key和value,key代表键值,value表示与key对应的信息。

2. set

2.1 set的概念

在这里插入图片描述

  1. set存储的是具有一定次序(升序和降序)的元素。
  2. set存储的元素被const修饰,不可更改。为什么?因为set的底层是用二叉搜索树实现的,改变了元素会影响次序。
  3. 用迭代器遍历set,可以得到有序序列。
  4. set中的元素是唯一的,因此使用set会去重。
  5. set看起来存放的只有key值,实际底层存放的是<value,value>键值对。

2.2 set的常见接口

  1. 构造

在这里插入图片描述

  1. 迭代器

在这里插入图片描述

void test1()
{//构造空setset<int> s1;s1.insert(3);s1.insert(2);s1.insert(4);s1.insert(5);s1.insert(1);auto it = s1.begin();//用迭代器遍历set,可以得到有序序列。while (it != s1.end()){cout << *it << " ";++it;}cout << endl;//用迭代器构造setset<int>s2(s1.begin(), s1.end());for (auto e : s2){cout << e << " ";}cout << endl;//拷贝构造set<int>s3(s2);for (auto e : s3){cout << e << " ";}cout << endl;
}

在这里插入图片描述

  1. 容量

在这里插入图片描述

  1. 增加

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

在这里插入图片描述

  1. 删除

在这里插入图片描述
若删除的参数是键值,键值存在就删除,不存在也不会报错。若删除的参数是迭代器,迭代器是end(),就会报错。

void test2()
{set<int> s1;s1.insert(3);s1.insert(2);s1.insert(4);s1.insert(5);s1.insert(1);auto it = s1.find(6);s1.erase(6);//✔//s1.erase(it);//❌
}
  1. 交换

在这里插入图片描述

  1. 清理

在这里插入图片描述

void test3()
{set<int> s1;s1.insert(3);s1.insert(2);s1.insert(4);s1.insert(5);s1.insert(1);int arr[] = { 9,8,7,6,5,4,3,2,1,0 };set<int>s2(arr, arr + sizeof(arr) / sizeof(arr[0]));//交换s1和s2s1.swap(s2);cout << "s1的元素:" ;for (auto e : s1){cout << e << " ";}cout << endl;cout << "s2的元素:";for (auto e : s2){cout << e << " ";}cout << endl;//清理s1s1.clear();cout <<"s1大小为:" << s1.size() << endl;cout << "s1是否为空:" << s1.empty() << endl;
}

在这里插入图片描述

  1. 查找

在这里插入图片描述
(1)查找键值为val的元素,找到了返回该元素在set中的迭代器,找不到返回end()的迭代器。
(2)库里的find和set的find有区别。库里的find是暴力查找,时间复杂度是O(N),set的find是大于查找元素就往左找,小于查找元素就往右找。

  1. 计数

在这里插入图片描述
返回set中与val相等的元素个数。由于set会去重 ,元素都是唯一,所以count只能返回0或者1,所以count也可以用来判断元素是否在set中。

  1. 获得迭代器区间

在这里插入图片描述
(1)lower_bound找到>=参数的元素的迭代器,upper_bound找到>参数的最小元素的迭代器。配合使用,可以获得左闭右开的区间。
(2)若两个函数的参数相同,则区间内的元素都是相同的,但set的元素是唯一的,所以这两函数用处不大,可以用于multiset。
(3)若参数在set中找不到,则返回set的end()的迭代器。

void test4()
{int arr[] = { 9,8,7,6,5,4,3,2,1,0 };set<int>s1(arr, arr + sizeof(arr) / sizeof(arr[0]));auto begin = s1.lower_bound(5);auto end = s1.upper_bound(10);while (begin != end){cout << *begin << " ";++begin;}cout << endl;
}

在这里插入图片描述

  1. 获得相同元素的迭代器区间

在这里插入图片描述
(1)在set中查找相同元素的区间,返回左闭右开的区间。
(2)返回键值对,键值对的第一个迭代器是set中val的位置,第二个迭代器是set中大于val的最小元素的位置。
(3)对于set来说,用处不大,因为set不能有重复的元素,但对multiset就有用处。
(4)若参数不存在于set,返回类似于[参数,参数)这样不存在的区间。

void test5()
{int arr[] = { 9,8,7,6,5,4,3,2,1,0 };set<int>s1(arr, arr + sizeof(arr) / sizeof(arr[0]));auto ret = s1.equal_range(5);auto itlow = ret.first;//找到5auto itupper = ret.second;//找到比5大的最小元素while (itlow != itupper){cout << *itlow << " ";++itlow;}cout << endl;
}

在这里插入图片描述

3. multiset

  1. multiset是在set的基础上,加上可以插入重复元素的功能。multiset依旧是按照一定次序(升序和降序)存储元素,通过迭代器遍历元素可以得到有序序列。multiset的元素可以重复,不能修改。
  2. equal_range和count对于multiset用处更大,更有意义。
void test6()
{int arr[] = { 9,8,7,6,5,4,3,2,1,0 ,1,2,3,4,5,6,7,8,9 };multiset<int> ms(arr,arr+sizeof(arr)/sizeof(arr[0]));cout << "multiset的元素:";for (auto& e : ms){cout << e << " ";}cout << endl;cout<<"9出现的次数:"<<ms.count(9)<<endl;auto range = ms.equal_range(5);auto low_range = range.first;auto upper_range = range.second;while (low_range != upper_range){cout << *low_range << " ";++low_range;}cout << endl;
}

在这里插入图片描述


4. map

4.1 map的概念

在这里插入图片描述

  1. map也是关联式容器,存储的是具有一定次序(升序和降序)的元素。
  2. map中存放的是<key,value>键值对,key代表键值,value表示与key对应的信息。map中元素的次序就是根据key进行排序的,因此key不能修改,且key在map中唯一,value则不一定唯一。
//键值对的定义  
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){}
};
  1. map通过迭代器遍历元素,可以得到有序序列。
  2. 特点:map支持[]访问,通过[key]可以找到对应的value。operator[]中实际进行插入查找。

4.2 map的常见接口

  1. 构造

在这里插入图片描述

  1. 迭代器

在这里插入图片描述
set的迭代器都是const迭代器,因此它的key不能修改,map的迭代器和const迭代器分明,key不可修改,value可以修改。
在这里插入图片描述
在这里插入图片描述

//例子
void test()
{map<string,string> dict;//词典//插入键值对dict.insert({"insert", "插入"});dict.insert({"erase", "删除"});dict.insert({"size", "大小"});dict.insert({"find","查找"});//为什么要将key和value封装?因为C++不支持返回两个值,但支持返回一个结构体auto it = dict.begin();while (it != dict.end()){//cout << *it << " ";//❌,pair不支持流插入cout << it->first << ":" << it->second << endl;++it;}cout << endl;//范围forfor (auto& e : dict){cout << e.first << ":" << e.second << endl;}
}

在这里插入图片描述

  1. 插入

在这里插入图片描述
(1)key与value通过成员类型value_type绑定在一起,为其取别名称为pair:typedef pair<const key, T> value_type;。
(2)不同于set,map插入的是键值对,不是单独的value。返回的也是键值对,插入成功,iterator是新插入节点的位置,bool是true;发现map已有相同的key,插入失败,iterator是map中key的位置,bool是false。
(3)如何插入键值对

//map
void test7()
{map<string,string> dict;//词典//法1//pair也是一个类模板pair<string, string>word1("insert", "插入");dict.insert(word1);//法2//先调用构造,再调用拷贝构造,编译器会优化为构造dict.insert(pair<string, string>("erase", "删除"));//法3//make_pair是模板函数,可以构造键值对dict.insert(make_pair("size", "大小"));//法4//C++11支持多参数的构造函数隐式类型转换,C++98支持单参数的构造函数隐式类型转换dict.insert({ "find","查找" });//等价于pair<string,string> word2 = {"find","查找"},然后dict.insert(word2);
}

在这里插入图片描述
最常用的是法3和法4。

  1. []下标访问
//例子:统计次数
//常规做法
void test9()
{string arr[] = { "西瓜", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };map<string, int> countMap;for (auto e : arr){auto it = countMap.find(e);if (it == countMap.end()){countMap.insert(make_pair(e, 1));}else{it->second++;}}for (const auto& kv : countMap){cout << kv.first << ":" << kv.second << endl;}
}
//优化
void test9()
{// 统计次数string arr[] = { "西瓜", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };map<string, int> countMap;for (auto e : arr){countMap[e]++;}for (const auto& kv : countMap){cout << kv.first << ":" << kv.second << endl;}
}

把key放入[]中,就可以得到相应的value,可问题是还没插入怎么++?[]下标访问,先试着插入key,如果key已经存在,则返回key对应的value,此时就可以对value操作。如果key不存在,先插入key,再返回对应的value。

//底层类似这样定义
T& operator[](cosnt K& key)
{pair<iterator,bool>ret = insert(make_pair(key,T()));//因为value可能是其他类型,所以不能单纯用int。//(1)key已在map里面,返回pair<map中key所在节点的位置,false>//(2)key不在map里面,返回pair<新插入key所在节点的位置,true>return ret->first->second;
}

练习
有效的括号

class Solution {
public://将左括号入栈,遇到右括号出栈,判断是否相同,不相等就return false,bool isValid(string s) {stack<char> st;map<char,char> m;m['('] = ')';m['['] = ']';m['{'] = '}';for(auto e:s){//如果e等于左括号,返回1,就入栈if(m.count(e)){st.push(e);}//遇到右括号,就出栈,判断是否相等else{if(st.empty()){return false; }char tmp = st.top();st.pop();if(m[tmp]!=e){return false;}}}if(st.empty()){return true;}return false;}
};

5. multimap

multimap和map的唯一不同就是:map中的key是唯一的,而multimap中key是可以重复的。因此multimap不支持[]下标访问。


6. 练习

  1. 两个数组的交集
class Solution {
public:vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {//先将两个数组放进set中,可以帮助去重//法1:遍历一个set中所有元素,判断在不在另一个set中,在就加到交集中//法2:从头开始,比较两个set中的元素,相等就是加到交集,然后同时++,小的就指向下一个元素,继续比较set<int>s1(nums1.begin(),nums1.end());set<int>s2(nums2.begin(),nums2.end());vector<int>v;//存放交集auto it1 = s1.begin();auto it2 = s2.begin();while(it1!=s1.end()&&it2!=s2.end())if(*it1==*it2){v.push_back(*it1);++it1;++it2;}else if(*it1>*it2){++it2;}else{++it1;}return v;}
};
  1. 前k个高频单词
class Solution {
public:struct Greater{bool operator()(const pair<string,int>& p1,const pair<string,int>&p2){return p1.second>p2.second;}};vector<string> topKFrequent(vector<string>& words, int k) {//法一:先将words的单词map中,可以起到去重和计数的作用map<string,int> m;for(auto& e:words){m[e]++;}//此时map已经按照字典序排好了//再按照单词出现频率排序,使用sort进行排序,但是sort不能对map排序,因为map的迭代器是双向的,双向迭代器不能使用随机迭代器的函数。所以将map的键值对加到vector中,就可以用sort。vector<pair<string,int>> v(m.begin(),m.end());//但是sort底层是快排,快排不稳定,排序结束后,出现频率相同的单词的字典序可能被破坏,所以得用另一个函数stable_sort,stable_sort不会破坏字典序。//又因为是排降序,得自己写仿函数stable_sort(v.begin(),v.end(),Greater());//排序后需要将前K个string取出,放入vectorvector<string> ret;for(int i = 0;i<k;i++){ret.push_back(v[i].first);}return ret;}
};
class Solution {
public://法2:如果偏要用sort排序,怎么办?修改仿函数,在频率相同的情况下不改变字典序。struct Greater{bool operator()(const pair<string,int>& p1,const pair<string,int>&p2){return (p1.second>p2.second) ||(p1.second==p2.second&&p1.first<p2.first);}};vector<string> topKFrequent(vector<string>& words, int k) {map<string,int> m;for(auto& e:words){m[e]++;}vector<pair<string,int>> v(m.begin(),m.end());sort(v.begin(),v.end(),Greater());vector<string> ret;for(int i = 0;i<k;i++){ret.push_back(v[i].first);}return ret;}
};
class Solution {
public://法3:用map按字典序排序,用multimap再按频率排序,multimap排序是稳定的,不会破坏字典序。vector<string> topKFrequent(vector<string>& words, int k) {map<string,int> m;for(auto& e:words){m[e]++;}multimap<int,string,greater<int>>mm;for(auto&e:m){mm.insert(make_pair(e.second,e.first));}vector<string>ret;auto it = mm.begin();while(k--){ret.push_back(it->second);++it;}return ret;}   
};

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

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

相关文章

日本橙皮书数据库—《医疗用医药品质量情报集》

日本橙皮书是一份关于医疗用医药品质量情报的汇总报告&#xff0c;由日本厚生劳动省发布。它主要涵盖了药品的品质再评价信息&#xff0c;特别是针对特定历史阶段的产品&#xff0c;笔者总结信息如下&#xff1a; ①日本橙皮书数据库包含了一系列药品的详细信息&#xff0c;如…

43、基于 springboot 自动配置的 spring mvc 错误处理,就是演示项目报错后,跳转到自定义的错误页面

Spring MVC 的错误处理&#xff1a;基于 SpringBoot 自动配置之后的 Spring MVC 错误处理。 就是访问方法时出错&#xff0c;然后弄个自定义的错误页面进行显示。 ★ 两种错误处理方式 方式一&#xff1a; 基于Spring Boot自动配置的错误处理方式&#xff0c;只要通过属性文件…

原生js实现轮播图及无缝滚动

我这里主要说轮播图和无缝滚动的实现思路&#xff0c;就采用最简单的轮播图了&#xff0c;当然实现的思路有很多种&#xff0c;我这也只是其中一种。 简单轮播图的大概结构是这样的&#xff0c;中间是图片&#xff0c;二边是箭头可以用来切换图片&#xff0c;下面的小圆点也可以…

Unity3d C#实现调取网络时间限制程序的体验时长的功能

前言 如题的需求应该经常在开发被提到&#xff0c;例如给客户体验3–5天的程序&#xff0c;到期后使其不可使用&#xff0c;或者几年的使用期限。这个功能常常需要使用到usb加密狗来限制&#xff0c;当然这也的话就需要一定的硬件投入。很多临时提供的版本基本是要求软件来实现…

代理模式 静态代理和动态代理(jdk、cglib)——Java入职第十一天

一、代理模式 一个类代表另一个类去完成扩展功能,在主体类的基础上,新增一个代理类,扩展主体类功能,不影响主体,完成额外功能。比如买车票,可以去代理点买,不用去火车站,主要包括静态代理和动态代理两种模式。 代理类中包含了主体类 二、静态代理 无法根据业务扩展,…

在ubuntu上安装ns2和nam(ubuntu16.04)

在ubuntu上安装ns2和nam 版本选择安装ns2安装nam 版本选择 首先&#xff0c;版本的合理选择可以让我们避免很多麻烦 经过测试&#xff0c;ubuntu的版本选择为ubuntu16.04&#xff0c;ns2的版本选择为ns-2.35&#xff0c;nam包含于ns2 资源链接(百度网盘) 链接:https://pan.bai…

简单数学题:找出最大的可达成数字

来看一道简单的数学题&#xff1a;力扣2769. 找出最大的可达成数字 题目描述的花里胡哨&#xff0c;天花乱坠&#xff0c;但这道题目非常简单。我们最多执行t次操作&#xff0c;只需每次操作都让x-1&#xff0c;让num1&#xff0c;执行t次操作后&#xff0c;x就变为xt&#xff…

腾讯音乐如何基于大模型 + OLAP 构建智能数据服务平台

本文导读&#xff1a; 当前&#xff0c;大语言模型的应用正在全球范围内引发新一轮的技术革命与商业浪潮。腾讯音乐作为中国领先在线音乐娱乐平台&#xff0c;利用庞大用户群与多元场景的优势&#xff0c;持续探索大模型赛道的多元应用。本文将详细介绍腾讯音乐如何基于 Apach…

基于蛇优化算法优化的BP神经网络(预测应用) - 附代码

基于蛇优化算法优化的BP神经网络&#xff08;预测应用&#xff09; - 附代码 文章目录 基于蛇优化算法优化的BP神经网络&#xff08;预测应用&#xff09; - 附代码1.数据介绍2.蛇优化优化BP神经网络2.1 BP神经网络参数设置2.2 蛇优化算法应用 4.测试结果&#xff1a;5.Matlab代…

java+springboot+mysql水电管理系统

项目介绍&#xff1a; 本系统为新版基于SpringBoot的水电管理系统&#xff1a; 使用javaspringbootmysql开发的水电费管理系统&#xff0c;系统包含超级管理员&#xff0c;系统管理员、用户角色&#xff0c;功能如下&#xff1a; 超级管理员&#xff1a;管理员管理、用户管理…

RK3588开发板编译环境Ubuntu20.04编译配置增加交换内存

迅为提供的编译环境 Ubuntu20.04 默认配置了交换内存是 9G&#xff0c;如果在编译过程中&#xff0c;因内 存不够而编译报错&#xff0c;可以参考本小节进行设置。 这里举例分配 5G 交换内存。 在开始之前&#xff0c;使用命令检查一下您的 ubuntu 的 swap 分区。 sudo swa…

Java从入门到精通-流程控制(一)

流程控制 1.复合语句 复合语句&#xff0c;也称为代码块&#xff0c;是一组Java语句&#xff0c;用大括号 {} 括起来&#xff0c;它们可以被视为单个语句。复合语句通常用于以下情况&#xff1a; - 在控制结构&#xff08;如条件语句和循环&#xff09;中包含多个语句。 - …

直播预约|哪吒汽车岳文强:OEM和Tier1如何有效对接网络安全需求

信息安全是一个防护市场。如果数字化程度低&#xff0c;数据量不够&#xff0c;对外接口少&#xff0c;攻击成本高&#xff0c;所获利益少&#xff0c;自然就没有什么攻击&#xff0c;车厂因此也不需要在防护上花费太多成本。所以此前尽管说得热闹&#xff0c;但并没有太多真实…

Redis全局命令

"那篝火在银河尽头~" Redis-cli命令启动 现如今&#xff0c;我们已经启动了Redis服务&#xff0c;下⾯将介绍如何使⽤redis-cli连接、操作Redis服务。客户端与服务端交互的方式有两种: ● 第⼀种是交互式⽅式: 后续所有的操作都是通过交互式的⽅式实现&#xff0c;…

vnc与windows之间的复制粘贴

【原创】VNC怎么和宿主机共享粘贴板 假设目标主机是linux&#xff0c;终端主机是windows&#xff08;就是在windows上使用VNC登陆linux&#xff09; 在linux中执行 vncconfig -nowin& 在linux选中文字后&#xff0c;无需其他按键&#xff0c;直接在windows中可以黏贴。 …

操作系统备考学习 day1 (1.1.1-1.3.1)

操作系统备考学习 day1 计算机系统概述操作系统的基本概念操作系统的概念、功能和目标操作系统的四个特征并发共享虚拟异步 操作系统的发展和分类操作系统的运行环境操作系统的运行机制 年初做了一个c的webserver 的项目&#xff0c;在学习过程中已经解除部分操作系统的知识&am…

K-Means(K-均值)聚类算法理论和实战

目录 K-Means 算法 K-Means 术语 K 值如何确定 K-Means 场景 美国总统大选摇争取摆选民 电商平台用户分层 给亚洲球队做聚类 ​编辑 其他场景 K-Means 工作流程 K-Means 开发流程 K-Means的底层代码实现 K-Means 的评价标准 K-Means 算法 对于 n 个样本点来说&am…

Golang Gorm 一对多的添加

一对多的添加有两种情况&#xff1a; 一种是添加用户的时候同时创建文章其次是创建文章关联已经存在的用户 添加用户的时候同时创建文章 package mainimport ("gorm.io/driver/mysql""gorm.io/gorm" )// User 用户表 一个用户拥有多篇文章 type User stru…

探索未来金融科技 SCF新加坡举办启动盛会

金融科技的热潮涌向新加坡&#xff0c;令人瞩目的SCF金融公链启动会于8月13日隆重举行。这场盛宴不仅为金融科技领域注入了新的活力&#xff0c;更为广大投资者、合作伙伴以及热衷区块链发展的人士提供了一次宝贵的交流机会。 在SCF金融公链启动会上&#xff0c;William Thomps…

【附安装包】Eplan2022安装教程

软件下载 软件&#xff1a;Eplan版本&#xff1a;2022语言&#xff1a;简体中文大小&#xff1a;1.52G安装环境&#xff1a;Win11/Win10/Win8/Win7硬件要求&#xff1a;CPU2.5GHz 内存4G(或更高&#xff09;下载通道①百度网盘丨64位下载链接&#xff1a;https://pan.baidu.co…