C++_map与set

news2024/11/16 8:28:59

目录

一、set

1、set的用法

2、multiset

二、map

1、map的用法 

2、map的operator[]

3、multimap

结语


前言:

        C++中的map和set容器属于关联式容器,与序列式容器不同的地方在于(序列式容器即vector、list,其底层是由线性数据结构实现的容器),关联式容器存储的是键值对,键值对是一个结构体,他只有两个成员变量:key,value,并且key和value是一一对应的,key表示键值,而value就是key对应的数据。

        关联式容器的底层由两种结构实现:树型结构(红黑树)、哈希结构。树型结构实现的容器有:map、multimap、set、multiset,哈希结构实现的容器有:unordered_map和unordered_set,本文着重介绍树型结构实现的容器。正是因为关联式容器在底层的结构上采用比序列式容器更为复杂的结构,所以关联式容器在查找数据时效率较序列式容器更高。

一、set

template < class T,                        
           class Compare = less<T>,        
           class Alloc = allocator<T>      
           > class set;

1、set的用法

        set只有唯一标识数据,即:value,但是这个value属于键值,也就是前面讲到的key,简单来说就是set在底层也是以键值对存放的,只不过键值对中不是<key,value>,而是<value,value>。并且通过value的值来确定其存放的顺序。

        set作为STL的容器之一,自然是可以实现数据的存储,只不过一般容器可以实现增删查改的功能,而set只能实现增删查的功能,原因就在于set的底层是红黑树(搜索二叉树),存放在set中的数据实际上存储在红黑树的节点中,红黑树的节点都是按照严格的规则进行摆放的,若修改一个数则会导致大消耗的调整,因此set不允许修改数据。但也正是红黑树,所以在迭代数据时,可以按照大小来打印数据(中序遍历树结构)。

        set的测试代码如下:

#define _CRT_SECURE_NO_WARNINGS 1

#include<set>
#include<iostream>
using namespace std;

int main()
{
	set<int> s1;
	//插入大量重复数据
	s1.insert(3);
	s1.insert(1);
	s1.insert(4);
	s1.insert(1);
	s1.insert(2);
	s1.insert(1);
	s1.insert(3);

	set<int>::iterator it1 = s1.begin();
	while (it1 != s1.end())//迭代器遍历
	{
		cout << *it1 << " ";
		++it1;
	}
	cout << endl;

	s1.erase(3);//删除3

	// 打印删除后数据
	for (auto e : s1)
	{
		cout << e << " ";
	}
	cout << endl;

	return 0;
}

        运行结果:

        从结果可以看到,set还具备去重的功能,并且打印出来的数据是具有顺序的,这些set的自带功能在特殊的场景下用起来是非常方便的。

        但是有一个问题,对象s1的类型是int,虽然底层存放的是键值对<value,value>,但是到了用户使用的应用层做了优化,只需要显示传递一个value类型即可,否则set的模板参数显示传递就要写<int,int>了,过于麻烦。

2、multiset

        multiset与set的区别在于:multiset允许存储重复的值。并且删除的值如果是重复的,那么该值都会被删除。

        multiset测试代码如下:

#define _CRT_SECURE_NO_WARNINGS 1

#include<set>
#include<iostream>
using namespace std;

int main()
{
	multiset<int> s1;
	//插入大量重复数据
	s1.insert(3);
	s1.insert(1);
	s1.insert(4);
	s1.insert(1);
	s1.insert(2);
	s1.insert(1);
	s1.insert(3);

	set<int>::iterator it1 = s1.begin();
	while (it1 != s1.end())//迭代器遍历
	{
		cout << *it1 << " ";
		++it1;
	}
	cout << endl;

	s1.erase(3);//删除3

	// 打印删除后数据
	for (auto e : s1)
	{
		cout << e << " ";
	}
	cout << endl;

	return 0;
}

        运行结果:

二、map

template < class Key,                                     
           class T,                                       
           class Compare = less<Key>,                     
           class Alloc = allocator<pair<const Key,T> >    
           > class map;

1、map的用法 

        map与set的区别在于,map的键值对是<key,value>,通常用pair结构体来表示这个键值对。以key的值来确定每个pair类型元素的顺序序列并且key所在的元素必须唯一(即去重),value的值是与key相关联的数据。

        pair结构体的结构如下:

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)//带参数的构造函数
{}
};

        map测试代码如下:

#define _CRT_SECURE_NO_WARNINGS 1

#include<iostream>
#include<map>
using namespace std;

int main()
{
	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", "计数"));

	auto dit = dict.begin();
	while (dit != dict.end())
	{
		//先对迭代器dit解引用拿到pair结构体,然后在解引用拿到pair中的成员first和second
		cout << (*dit).first << ":" << (*dit).second << endl;
		++dit;
	}
	cout << endl;
	
	return 0;
}

        运行结果:

        从结果可以看到,map的插入函数需要手动构建一个pair作为该函数的实参,而这里用到的make_pair是一个函数模板,该函数会返回一个pair对象,这样就能够达到inset函数的要求了。

        具体示意图如下:

2、map的operator[]

        map的operator[]运算符重载用法很经典,我们对[]的认识是,他可以查看数组中某一位置的值,并且可以修改这个元素,而map的operator[]在以上功能的前提下还具备插入功能,只不过对map的[]修改是更改value的内容,而不更改key的内容,同理通过[]对map的查看是查看元素中value的值。


        以下map的operator[]的实现示意图可以更好的解释其功能:

         ret是一个对象,他用来接收Insert的返回值,他跟Insert的make_pair返回的临时对象是两个对象,ret对象中里面有一个迭代器,该迭代器指向通过Insert函数插入到map中pair元素。operator[]的返回值实际上就是通过ret找到插入元素的第二个成员变量value,并且返回他的引用,所以[]可以更改map中元素的value数据。

        测试operator[]的代码如下:

#define _CRT_SECURE_NO_WARNINGS 1

#include<iostream>
#include<map>
using namespace std;

int main()
{
	map<string, string> dict;
	dict.insert(make_pair("sort", "排序"));
	dict.insert(make_pair("string", "字符串"));
	dict.insert(make_pair("count", "计数"));

	dict["ZH"];	// 成功插入,但是value值没有显示给,因此value调用string的默认构造--即nullptr
	dict["OBJ"] = "后缀"; // 插入+修改,插入的元素key为OBJ,value从nullptr修改成"后缀"
	dict["sort"] = "(排序)"; // 修改,将key:sort从原来的排序修改为“排序”
	cout << dict["sort"] << endl; // 查找,打印sort的value
	cout << endl;

	auto dit = dict.begin();
	while (dit != dict.end())
	{
		//cout << (*dit).first << ":" << (*dit).second << endl;
		cout << dit->first << ":" << dit->second << endl;

		++dit;
	}
	cout << endl;

	return 0;
}

        运行结果:

        注意:所以map插入和修改都是可以直接用【】,但是【】的查找功能用起来会有弊端,如果要查找的元素不在map里面就会自动插入一个该元素,失去了单纯查找的本意。 

3、multimap

        multimap与map的区别在于:前者允许key值冗余,即不会对数据起到去重的作用。

        multimap测试代码如下:

#define _CRT_SECURE_NO_WARNINGS 1

#include<iostream>
#include<map>
using namespace std;

int main()
{
	multimap<string, string> dict;
	dict.insert(make_pair("sort", "排序"));
	dict.insert(make_pair("sort", "排序"));
	dict.insert(make_pair("string", "字符串"));
	dict.insert(make_pair("string", "字符串"));
	dict.insert(make_pair("count", "计数"));
	dict.insert(make_pair("count", "计数"));

	auto dit = dict.begin();
	while (dit != dict.end())
	{
		//cout << (*dit).first << ":" << (*dit).second << endl;
		cout << dit->first << ":" << dit->second << endl;

		++dit;
	}
	cout << endl;

	return 0;
}

        运行结果:

结语

        以上就是关于map和set以及multimap、multiset的讲解,实际中map和set还是用的最多,他们的区别无非在于set只有一个value作为key键值而map中即有key键值也有与其对应的value键值,也正是因为set没有value键值,所以set没有实现‘[]'的运算符重载,而map实现了‘[]'的运算符重载。

        最后希望本文可以给你带来更多的收获,如果本文对你起到了帮助,希望可以动动小指头帮忙点赞👍+关注😎+收藏👌!如果有遗漏或者有误的地方欢迎大家在评论区补充,谢谢大家!!

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

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

相关文章

牛客禁用题:求阶乘

思路&#xff1a;在新类中使用全局变量进行运算&#xff0c;在主类中定义新类数组&#xff0c;通过构造函数的调用次数返回阶乘 #include <type_traits> class add{public:static int count;static int tmp;add(){countcounttmp;tmp;} }; int add::count0; int add::t…

Flink:动态表 / 时态表 / 版本表 / 普通表 概念区别澄清

博主历时三年精心创作的《大数据平台架构与原型实现&#xff1a;数据中台建设实战》一书现已由知名IT图书品牌电子工业出版社博文视点出版发行&#xff0c;点击《重磅推荐&#xff1a;建大数据平台太难了&#xff01;给我发个工程原型吧&#xff01;》了解图书详情&#xff0c;…

在golang中使用protoc

【Golang】proto生成go的相关文件 推荐个人主页&#xff1a;席万里的个人空间 文章目录 【Golang】proto生成go的相关文件1、查看proto的版本号2、安装protoc-gen-go和protoc-gen-go-grpc3、生成protobuff以及grpc的文件 1、查看proto的版本号 protoc --version2、安装protoc-…

Java 打包 SpringBoot 项目报错

Java 打包 SpringBoot 项目报错 问题重现 Please refer to xxxx for the individual test results. Please refer to dump files (if any exist) [date].dump, [date]-jvmRun[N].dump and [date].dumpstream. 解决问题 在 pom.xml 的 <properties> 中添加项目代码 <s…

AIGC下一步:如何用AI再度重构或优化媒体处理?

让媒资中“沉默的大多数”再次焕发光彩。 邹娟&#xff5c;演讲者 编者按 AIGC时代下&#xff0c;媒体内容生产领域随着AI的出现也涌现出更多的变化与挑战。面对AI的巨大冲击&#xff0c;如何优化或重构媒体内容生产技术架构&#xff1f;在多样的应用场景中媒体内容生产技术又…

【半监督医学图像分割 2021 IEEE】DU-GAN

【半监督医学图像分割 2021 IEEE】DU-GAN 论文题目&#xff1a;DU-GAN: Generative Adversarial Networks with Dual-Domain U-Net Based Discriminators for Low-Dose CT Denoising 中文题目&#xff1a;基于双域U-Net鉴别器的生成对抗网络用于低剂量CT去噪 论文链接&#xff…

云时代【5】—— LXC 与 容器

云时代【5】—— LXC 与 容器 三、LXC&#xff08;一&#xff09;基本介绍&#xff08;二&#xff09;相关 Linux 指令实战&#xff1a;使用 LXC 操作容器 四、Docker&#xff08;一&#xff09;删除、安装、配置&#xff08;二&#xff09;镜像仓库1. 分类2. 相关指令&#xf…

C---输入5个字符串,找出最长字符串并输出

从键盘输入5个字符串&#xff0c;找出最长的字符串并输出该字符串 例&#xff1a; 输入&#xff1a;123 1234 werere1234 12 123 输出&#xff1a;werere1234 #include <stdio.h> #include <string.h>int main() {char strings[5][80]; // 存储5个字符串&#x…

界面控件DevExpress .NET MAUI v23.2新版亮点 - 拥有全新的彩色主题

DevExpress拥有.NET开发需要的所有平台控件&#xff0c;包含600多个UI控件、报表平台、DevExpress Dashboard eXpressApp 框架、适用于 Visual Studio的CodeRush等一系列辅助工具。屡获大奖的软件开发平台DevExpress 今年第一个重要版本v23.1正式发布&#xff0c;该版本拥有众多…

记录SSM项目集成Spring Security 4.X版本 之 加密验证和记住我功能

目录 前言 一、用户登录密码加密认证 二、记住我功能 前言 本次笔记的记录是接SSM项目集成Spring Security 4.X版本 之 加入DWZ,J-UI框架实现登录和主页菜单显示-CSDN博客https://blog.csdn.net/u011529483/article/details/136255768?spm1001.2014.3001.5502 文章之后补…

腾讯云幻兽帕鲁服务器使用Linux和Windows操作系统,对用户的技术要求有何不同?

腾讯云幻兽帕鲁服务器使用Linux和Windows操作系统对用户的技术要求有何不同&#xff1f; 首先&#xff0c;从操作界面的角度来看&#xff0c;Windows操作系统相对简单易操作&#xff0c;适合那些偏好使用图形化界面操作的用户。而Linux操作系统则需要通过命令行完成&#xff0…

springboot基于保信息学科平台系统设计与实现论文

基于保密信息学科平台系统 摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了基于保密信息学科平台系统的开发全过程。通过分析基于保密信息学科平台系统管理的不足&#xff0c;创建了一个计算机管理基于保密信息…

MySQL:开始深入其数据(二)DQL

在初识MySQL中我们就知道了DQL只有一个关键字select。 可是数据库管理中我们用的最多的就是查询&#xff0c;为了方便我们使用&#xff0c;MySQL定义了大量关键字给我们使用&#xff0c;泪目。 文章目录 DQLselect语法指定查询字段where条件语句逻辑操作符比较操作符between a…

1.亿级积分数据分库分表:总体方案设计

项目背景 以一个积分系统为例&#xff0c;积分系统最核心的有积分账户表和积分明细表&#xff1a; 积分账户表&#xff1a;每个用户在一个品牌下有一个积分账户记录&#xff0c;记录了用户的积分余额&#xff0c;数据量在千万级积分明细表&#xff1a;用户每次积分发放、积分扣…

基于springboot+vue的在线考试与学习交流平台

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

猫猫与数列

来源&#xff1a;牛客网 示例1 输入 2 2 输出 5 示例2 输入 999999998 2 输出 3 示例3 输入 10 18 输出 3 #include <bits/stdc.h>#define endl \n using ll long long; typedef unsigned long long ull; using namespace std; void GordenGhost(); l…

科技企业如何做到FTP数据安全保护

在数字化浪潮的推动下&#xff0c;科技企业的数据已成为推动创新、提升效率、增强竞争力的核心资源。数据的重要性不言而喻&#xff0c;它不仅包含了客户信息、市场分析、产品设计等关键信息&#xff0c;更是企业宝贵的资产。然而&#xff0c;随着数据量的激增&#xff0c;数据…

《PyTorch深度学习实践》第十二讲循环神经网络基础

一、RNN简介 1、RNN网络最大的特点就是可以处理序列特征&#xff0c;就是我们的一组动态特征。比如&#xff0c;我们可以通过将前三天每天的特征&#xff08;是否下雨&#xff0c;是否有太阳等&#xff09;输入到网络&#xff0c;从而来预测第四天的天气。 我们可以看RN…

数据结构从入门到精通——顺序表

顺序表 前言一、线性表二、顺序表2.1概念及结构2.2 接口实现2.3 数组相关面试题2.4 顺序表的问题及思考 三、顺序表具体实现代码顺序表的初始化顺序表的销毁顺序表的打印顺序表的增容顺序表的头部/尾部插入顺序表的头部/尾部删除指定位置之前插入数据和删除指定位置数据顺序表元…

MySQL 主从读写分离入门——基本原理以及ProxySQL的简单使用

一、读写分离工作原理 读写分离的工作原理&#xff1a;在大型网站业务中&#xff0c;当单台数据库无法满足并发需求时&#xff0c;通过主从同步方式同步数据。设置一台主服务器负责增、删、改&#xff0c;多台从服务器负责查询&#xff0c;从服务器从主服务器同步数据以保持一…