深入篇【C++】set和map(multiset/multimap)特性总结与使用

深入篇【C++】set和map(multiset/multimap)特性总结与使用

  • 一.set/multiset总结
  • 二.map/multiset总结
  • 三.set/map应用

一.set/multiset总结

在这里插入图片描述

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

【函数注意1】

1.set具有排序+去重功能。
2.set的查找函数find:找到了会返回当前结点的迭代器,找不到就会返回最后一个位置的迭代器end()。
3.set还有count函数,这个是用来计算出现的个数的,但对于set而言来说没有用,因为set是去重后,的最后的结果要么是0要么是1,所以count函数还可以用来具有查找功能。
4.count函数主要用于mutilset,mutilset可以允许重复的数据。
5.set与multiset的区别就在于set里面的数据是唯一的,不能出现重复的,是去重的,而multiset是允许出现重复的,不去重的。

【结构注意2】

1. 与map/multimap不同,map/multimap中存储的是真正的键值对<key, value>,set中只放value,但在底层实际存放的是由<value,value>构成的键值对.
2. set中插入元素时,只需要插入value即可,不需要构造键值对。
3. set中的元素不可以重复(因此可以使用set进行去重)。
4. 使用set的迭代器遍历set中的元素,可以得到有序序列
5. set中的元素默认按照小于来比较compare=Less<.T.>
6. set中查找某个元素,时间复杂度为: l o g 2 n log_2 n log2n
7. set中的元素不允许修改(为什么---->const修饰)
8. set中的底层使用二叉搜索树即红黑树

二.map/multiset总结

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

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

2.底层封装一个pair类型的成员变量。存储着也是pair类型的对象,当要插入一个数据时,这个对象是pair类型的才可以被插入,所以可以使用匿名对象的形式插入

 dict.insert(pair<string, string>("run", "启动"));

也可以使用一个make_pair(T,T)函数来返回pair<.T>类型的对象

dict.insert(make_pair("string", "字符串"));

还可以以一种隐式类型转化的方式插入

 dict.insert({ "int","整形" });

这里会将这个数组类型转化成pair类型,怎么转化的?调用pair的构造函数,C++11支持双参构造函数调用时会发生隐式类型转化。

3.使用迭代器访问的不是真正的数据,而是pair类型的对象,所以要真正的访问数据,还需要进一步访问。而且第一个数据是不能被修改的,只能访问,第二个数据可以被修改可以被访问

map<string, string>::iterator it = dict.begin();

	while (it != dict.end())
	{
		//it是迭代器就相当于指针
		//正常是*it就是解引用到要访问的对象了,但这里的对象是pair不可以直接打印

		cout << (*it).first << (*it).second << endl;
		
		//it->first ="xxx";第一个数据不能被修改
		//it->second = "xxxx";第二个数据可以被修改
	    cout << it->first << it->second << endl;
	    //可以直接通过指针访问到里面的数据
		++it;
	}

4.对于map来说也是具有排序和去重功能,而且当插入相同的值。并不会插入进去,不会覆盖原来的数据。
5. 在内部,map中的元素总是按照键值key进行比较排序的。key是无法被修改的,而value的值可以被修改。
6. map中通过键值访问单个元素的速度通常比unordered_map容器慢,但map允许根据顺序对元素进行直接迭代(即对map中的元素进行迭代时,可以得到一个有序的序列)。
7. map通常被实现为二叉搜索树(更准确的说:平衡二叉搜索树(红黑树))。
8. map支持下标访问符,即在[]中放入key,就可以找到与key对应的value。只不过与正常的下标访问不同,而是传key值,给你返回的是value值的引用。[ ]的本质就是通过insert完成的。

insert的返回值是pair<iterator,bool>
在这里插入图片描述

①当key在树里面,返回的是pair<在树里面key对于结点的iterator,false>。
②当key不在树里面,返回的是pair<刚插入树里面对应结点的iterator,true>。
所以[]里面其实具有两个功能,一是将数据插入进去,二是返回对应key的value值的引用。

V& operator[](const K& key)
	{
		pair<iterator, bool> ret = insert(make_pair(key, V()));
		return ret.iterator->second;
	}
    map<string, string>kv;
	kv.insert(make_pair("apple", "苹果"));
	kv.insert(make_pair("yellow", "黄色"));
	kv.insert(make_pair("insert", "插入"));
    //[ ]具有读取value的功能
	//跟正常的[]类似,只不过map的[]读的是value值
	cout << kv["apple"] << endl;

	kv["sort"];//插入一个空value

	kv["sort"] = "排序";
	//修改
	kv["man"] = "男人";
	//插入+修改

【注意】

1. map中的的元素是键值对
2. map中的key是唯一的,并且不能修改
3. 默认按照小于的方式对key进行比较
4. map中的元素如果用迭代器去遍历,可以得到一个有序的序列
5. map的底层为平衡搜索树(红黑树),查找效率比较高 O ( l o g 2 N ) O(log_2 N) O(log2N)
6. 支持[]操作符,operator[]中实际进行插入查找。而multimap是不支持[],因为multimap一个key值可能对应多个value值,所以不知道返回哪一个了。

三.set/map应用

1.计算水果个数

void test3()
{
	string arr[] = { "西瓜", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };
	
	//map的find查找特点:当找到要要的key值后,会返回对应key-value的迭代器
	//如果没找到就会返回最后一个位置的后一个迭代器即end()
	map<string, int> count;
	for (auto e : arr)
	{
		auto ret = count.find(e);
		if (ret == count.end())//说明树里没有,那就插入进去,并给1
		{
			count.insert(make_pair(e, 1));
		}
		else//说明找到了,那就将对应的数字++
		{
			ret->second++;
		}
	}
	for (auto e : count)
	{
		cout << e.first << ":" << e.second << endl;
	}
	
}

另一种计算方法

for (auto e : arr)
	{
		count[e]++;
		//实现的原理:
		//第一步先插入,第二步返回value值
		//如果不存在就插入,并且value值就是匿名对象对应类型的缺省值,然后++就变成1
		// 如果存在插入也没事,不会覆盖,返回value 
	}

在这里插入图片描述
2.两个序列的交集
在这里插入图片描述

思路
1.两个序列中可能存在多个相同的数,但最终结点只会有一个,所以需要先去重,这就需要使用set。使用完set后,序列就变得有序了。
2.两个有序序列如何找交集呢?
交集:两个序列同时从头开始遍历,较小的一方就++,相同的就是交集然后再同时++。

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {

     //首先要考虑两个序列都去重,那就都放进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)
         {
            it1++;
         }
         else if(*it2<*it1)
         {
             it2++;
         }
         else 
         {
             v.push_back(*it1);
             it1++;
             it2++;
         }
     }
     return v;
    }
};

3.前K个高频单词
在这里插入图片描述
要求获取前k个出现最多的单词,不过这里还有个要求,当出现的次数相同时,就要按照字典序排序。

思路:
1.统计出现的次数我们可以利用map来统计。
2.再对根据出现的次数进行排序。选出前K个单词
3.不过这里的问题是当次数相同时,如何按照字典序再排序?
4.我们想map统计完后,单词的顺序是排序好的,每个单词的个数可能相同也可能不同。但如果当单词个数不相同时,对出现的个数排序就可以完成任务,因为没有出现相同的频率,但如果单词个数出现相同时,排序完后,如果它们的相对顺序没有被改变,那么也可以完成任务,因为相对顺序就是按照字典序排的,所以这个排序得要求是稳定的。
5.还有如何进行比较排序呢?我们需要使用仿函数来修改比较规则。根据次数进行比较,并且进行降序排序。

class Solution {
public:

  //要求先按照频率由高到低排序也就是出现的次数,如何统计出现的次数呢?用map统计次数


    struct Greater//仿函数重构比较方式,利用出现的次数进行比较,并且降序排,大的在前面,小的在后面
    {
    bool operator()(const pair<string,int>& kv1,const pair<string,int>& kv2)
    {
          return kv1.second>kv2.second;
    }
    };
    vector<string> topKFrequent(vector<string>& words, int k) {
        map<string,int> countmap;
        for(auto &e:words)
        {
            countmap[e]++;
        }
        //已经统计完次数了接下来就要按照出现的频率来排序,不过map其实已经按照字典序的排序方法将数据排好
        //只要要按照频率排序后稳定性不变,相对顺序不变就可以了,但sort稳定性不行
        //注意sort无法对map排序,所以我们可以将map里的数据放进vector里

        vector<pair<string,int>> v; 
        v(countmap.begin(),countmap.end());
        stable_sort(v.begin(),v.end(),Greater());
        //stable_sort排序比较稳定
        vector<string> vs;
       for(int i=0;i<k;i++)
       {
         vs.push_back(v[i].first);//选取前k个单词
       }
      return vs;
    }
};

还有一种方法,可以直接使用sort,不用管稳定不稳定,那就是直接更改sort的比较排序规则,除了按照次数进行降序排序外,再添加上,当次数相同时,就按照字典序对单词进行比较。

class Solution {
public:

  //要求先按照频率由高到低排序也就是出现的次数,如何统计出现的次数呢?用map统计次数


    struct Greater//仿函数重构比较方式
    {

    bool operator()(const pair<string,int>& kv1,const pair<string,int>& kv2)
    {
          return kv1.second>kv2.second||(kv1.second==kv2.second&&kv1.first<kv2.first);
          //大于就是降序前面大,后面小
    }

    };
    vector<string> topKFrequent(vector<string>& words, int k) {
        map<string,int> countmap;
        for(auto &e:words)
        {
            countmap[e]++;
        }
        //已经统计完次数了接下来就要按照出现的频率来排序,不过map其实已经按照字典序的排序方法将数据排好

        vector<pair<string,int>> v;
        v(countmap.begin(),countmap.end());
        sort(v.begin(),v.end(),Greater());
        //也可以利用仿函数的比较规则来使用sort排序,首先要按照频率比较,当频率相同时,按照字典序比较
       
        vector<string> vs;
       for(int i=0;i<k;i++)
       {
         vs.push_back(v[i].first);
       }
      return vs;
    }
};

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

服务器数据恢复-EVA存储磁盘故障导致存储崩溃的数据恢复案例

EVA系列存储是一款以虚拟化存储为实现目的的中高端存储设备。EVA存储中的数据在EVA存储设备工作过程中会不断进行迁移&#xff0c;如果运行的任务比较复杂&#xff0c;EVA存储磁盘负载加重&#xff0c;很容易出现故障的。EVA存储通过大量磁盘的冗余空间和故障后rss冗余磁盘动态…

“车-路-网”电动汽车充电负荷时空分布预测(matlab)

目录 1 主要内容 2 部分代码 3 程序结果 4 下载链接 1 主要内容 该程序参考《基于动态交通信息的电动汽车充电负荷时空分布预测》和《基于动态交通信息的电动汽车充电需求预测模型及其对配网的影响分析》文献模型&#xff0c;考虑私家车、出租车和共用车三类交通工具特性和…

诺依框架ruoyi.js添加默认当年日期范围

ruoyi.js添加方法 // 默认当年日期范围如&#xff1a;2023-01-01到2023-08-22&#xff08;至今&#xff09; export function defaultYearDate(data) {// this.dateDefaultShow new Date();// this.dateDefaultShow.setMonth(new Date().getMonth() - 1);const end new Date…

element-table的动态操作,自动以表格,动态新增行、列,删除行列

灵活的自定义表格行列以及增删改查的操作,右键选中列则是列的删除&#xff0c;效果如下 <template><div class"st-table"><div style"width: 100%"><el-button click"addRow()" type"primary" icon"CircleP…

【学习FreeRTOS】第17章——FreeRTOS任务通知

1.任务通知的简介 任务通知&#xff1a;用来通知任务的&#xff0c;任务控制块中的结构体成员变量 ulNotifiedValue就是这个通知值。 使用队列、信号量、事件标志组时都需另外创建一个结构体&#xff0c;通过中间的结构体进行间接通信&#xff01; 使用任务通知时&#xff0c…

Django学习笔记-AcApp端授权AcWing一键登录

笔记内容转载自 AcWing 的 Django 框架课讲义&#xff0c;课程链接&#xff1a;AcWing Django 框架课。 AcApp 端使用 AcWing 一键授权登录的流程与之前网页端的流程一样&#xff0c;只有申请授权码这一步有一点细微的差别&#xff1a; 我们在打开 AcApp 应用之后会自动向 AcW…

Mybatis-分页与动态字符

目录 一.Mybatis动态分页 什么是动态分页&#xff1a; 导入pom依赖 配置拦截器 编写Bookmapper文件 配置pageBean文件 配置BookBiz接口类 配置BookBizImpl实现接口类 编写实现类demo 测试结果 ​编辑 不走插件&#xff0c;不会分页 二.Mybatis的特殊字符 编写一个Book…

软件测试知识点总结(一)

文章目录 前言一. 什么是软件测试二. 软件测试和软件调试的区别三. 软件测试和研发的区别四. 优秀的测试人员所应该具备的素质总结 前言 在现实生活中的很多场景下&#xff0c;我们都会进行测试。 比如买件衣服&#xff0c;我们需要看衣服是不是穿着好看&#xff0c;衣服材质如…

java八股文面试[数据结构]——HashMap扩容优化

知识来源&#xff1a; 【2023年面试】HashMap在扩容上做了哪些优化_哔哩哔哩_bilibili

Ansible 自动化安装软件

例子如下&#xff1a; 创建一个名为/ansible/package.yml 的 playbook : 将 php 和 mariadb 软件包安装到 dev、test 和 prod 主机组中的主机上 将 RPM Development Tools 软件包组安装到 dev 主机组中的主机上 将 dev 主机组中主机上的所有软件包更新为最新版本 --- - name:…

k8s之工作负载、Deployment、DaemonSet、StatefulSet、Job、CronJob及GC

文章目录 1、工作负载1.1、定义1.2、分类 2、Deployment2.1、定义2.2、Deployment创建2.3、Deployment 更新机制2.3.1、比例缩放&#xff08;Proportional Scaling&#xff09;2.3.2、HPA&#xff08;动态扩缩容&#xff09;2.3.2.1、需要先安装metrics-server2.3.2.2、配置hpa…

JVM工具-1. jps:虚拟机进程状态工具

文章目录 1. jps介绍2. jps命令格式3. jps工具主要选项4. jps -q5. jps -m6. jps -l7. jps -v 1. jps介绍 jps(JVM Process Status Tool)&#xff1a;虚拟机进程状态工具&#xff0c;可以列出正在运行的虚拟机进程&#xff0c;并显示虚拟机执行主类&#xff08;Main Class&…

【UE5:CesiumForUnreal】——3DTiles数据属性查询和单体高亮

目录 0.1 效果展示 0.2 实现步骤 1 数据准备 2 属性查询 2.1 射线检测 2.2 获取FeatureID 2.3 属性查询 2.4 属性显示 3 单体高亮 3.1 构建材质参数集 3.2 材质参数设置 3.3 添加Cesium Encode Metadata插件 3.4 从纹理中取出特定FeatureId属性信息 3.5 创建…

netdata监控服务器主机(包括Docker容器)

效果 Docker部署 创建挂载目录 mkdir -p /data/netdata/{netdatacache,netdatalib}docker运行 docker run -d --namenetdata \-p 19999:19999 \-v /data/netdata/netdatalib:/var/lib/netdata \-v /data/netdata/netdatacache:/var/cache/netdata \-v /etc/passwd:/host/etc…

【业务功能篇83】微服务SpringCloud-ElasticSearch-Kibanan-docke安装-应用层实战

五、ElasticSearch应用 1.ES 的Java API两种方式 Elasticsearch 的API 分为 REST Client API&#xff08;http请求形式&#xff09;以及 transportClient API两种。相比来说transportClient API效率更高&#xff0c;transportClient 是通过Elasticsearch内部RPC的形式进行请求…

MAVEN利器:一文带你了解IDEA中如何使用Maven

前言&#xff1a; 强大的构建工具——Maven。作为Java生态系统中的重要组成部分&#xff0c;Maven为开发人员提供了一种简单而高效的方式来构建、管理和发布Java项目。无论是小型项目还是大型企业级应用&#xff0c;Maven都能帮助开发人员轻松处理依赖管理、编译、测试和部署等…

windows10 docker 安装在D盘

win10安装docker后发现c盘空间急速减少&#xff0c;360管家查看发现images镜像安装在C盘&#xff0c;于是重装docker desktop以为在安装过程中能够选择&#xff0c;遗憾的是没有提供选择权限&#xff0c;默认直接就安装到了c盘。 desktop 迁移 百度得知可以将c盘的docker安装…

SpringCloud学习笔记(二)_Eureka注册中心

一、Eureka简介 Eureka是一项基于REST&#xff08;代表性状态转移&#xff09;的服务&#xff0c;主要在AWS云中用于定位服务&#xff0c;以实现负载均衡和中间层服务器的故障转移。我们称此服务为Eureka Server。Eureka还带有一个基于Java的客户端组件Eureka Client&#xff…

网络安全之红蓝对抗实战

前言 背景介绍&#xff1a;目标是拿到企业www.xxx.com的《上市商业计划书.docx》&#xff0c;通过 OPENVPN 访问。特别提出的得分规则修改&#xff0c;权限的得分必须有 WEBSHELL/交互式 SHELL&#xff0c;只有一个漏洞回显不给分&#xff0c;更加偏向考察**漏洞利用**而非漏洞…