C++ map和set的使用

关联式容器
 

vector、list、deque统称为序列式容器,因为其底层为线性序列的数据结构,存储的是元素本身
侧重于单纯的存储数据

关联式容器也是用来存储数据的,里面存储的是<key, value>结构的键值对,在数据检索时比序列式容器效率更高
 

键值对
 

用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量key和value,key代
表键值,value表示与key对应的信息

如英汉字典,英文单词与其中文含义是一一对应的关系,二者构成一个键值对,通过该单词就可找到与之对应的中文含义

SGI-STL中关于键值对的定义:
 

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

STL总共实现了两种不同结构的关联式容器:树型结构与哈希结构

树型结构的关联式容器主要有四种:map、set、multimap、multiset
 

set
 

set的介绍
 

1 set是按照一定次序存储元素的容器
2 在set中,value就是key,类型为T,并且每个value必须是唯一的
   set中的元素不能在容器中修改(元素被const修饰)

3 set容器通过key访问单个元素的速度通常比unordered_set容器慢

4 set在底层是用二叉搜索树(红黑树)实现的

注意:
 

1 与map/multimap不同,map/multimap中存储的是真正的键值对<key, value>

   set中只放value,但在底层实际存放的是由<value, value>构成的键值对

2 set中的元素不可以重复(因此可以使用set进行去重)
3 使用set的迭代器遍历set中的元素,可以得到有序序列

4 set中的元素默认按照小于来比较

下面介绍的set和map的使用仅为精简版,均为使用较多的

set的使用:

1 查找在不在

2 排序+去重
 

T: set中存放元素的类型,set中插入元素时,只需要插入value,但实际在底层存储<value, value>的键值对
 Compare:set中元素默认按照小于来比较

Alloc:set中元素空间的管理方式,使用STL提供的空间配置器管理

insert:

 返回值是pair:

插入成功-> pair<新插入key所在节点的迭代器,true>

插入失败-> pair<已存在的key/value所在节点的迭代器,false>

erase:

 第一个版本的erase:(搭配find使用,需要进行判断)若不判断则给定无效的iterator会报错

                                                                                        给定正确的iterator会删除

 第二个版本的erase:无论要删除的key是否存在,均不报错,若存在就删除,不存在则无事发生

find: 

 若是找到了,则返回此元素所在节点的迭代器,否则返回set::end()

count:

统计key的个数,对于set而言用处不大,因为在set里,key非0即1,可以用于判断key在不在 

但对于multiset而言,count就有用武之地了,可以统计key的个数

测试1:

void test_set1()
{
	//1 查找在不在
	//2 排序+去重
	set<int> s;
	s.insert(4);
	s.insert(3);
	s.insert(8);
	s.insert(2);
	s.insert(4);
	s.insert(5);
	pair<set<int>::iterator,bool> ret = s.insert(2);
	cout << ret.second << endl;

	auto ret2 = s.insert(8);
	cout << ret2.second << endl;

	//迭代器遍历
	set<int>::iterator it = s.begin();
	while (it != s.end())
	{
        //*it = 10;//不可以,set不允许key/value被修改
		cout << *it << " ";
		it++;
	}
	cout << endl;

	//范围for
	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;

	s.erase(2);//删除存在的
	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;

	s.erase(11);//删除不存在的,无事发生

	set<int>::iterator it2 = s.find(8);//删除存在的
	s.erase(it2);
	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;

	//it2 = s.find(30);//删除不存在的
	//s.erase(it2); //报错,erase一个无效的迭代器程序会崩溃

	//正确处理:
	it2 = s.find(30);
	if (it2 != s.end())
	{
		s.erase(it2);
	}

	if (s.count(3))//可用于判断key是否存在
	{
		cout << "3存在" << endl;
	}
	else
	{
		cout << "3不存在" << endl;
	}
}

运行结果:

lower_bound:

 

返回>=val值位置的迭代器

 upper_bound:

返回>val值位置的迭代器

可能会用到:删除一段区间的值

 测试2:
void test_set2()
{
	set<int> myset;
	set<int>::iterator itlow, itup;

	for (int i = 1; i < 10; i++) 
		myset.insert(i * 10); // 10 20 30 40 50 60 70 80 90

	itlow = myset.lower_bound(30);  //返回key为30位置的迭代器           
	itup = myset.upper_bound(60);   //返回key为70位置的迭代器             

	myset.erase(itlow, itup);//左闭右开区间[30,70),删除[30,60]
	for (auto e : myset)
	{
		cout << e << " ";
	}
	cout << endl;

	set<int> myset2(myset);
	set<int>::iterator itlow2, itup2;

	for (int i = 1; i < 10; i++)
		myset2.insert(i * 10);// 10 20 30 40 50 60 70 80 90

	itlow2 = myset2.lower_bound(25);
	itup2 = myset2.upper_bound(70);
	myset2.erase(itlow2, itup2);//左闭右开区间[30,80),删除[30,60]
	for (auto e : myset2)
	{
		cout << e << " ";
	}
	cout << endl;
}

运行结果:

equal_range: 

 测试3:
void test_set3()
{
	set<int> myset;

	for (int i = 1; i <= 5; i++)
		myset.insert(i * 10); // myset: 10 20 30 40 50

	//pair<set<int>::iterator, set<int>::iterator> ret = myset.equal_range(35);
	auto ret = myset.equal_range(35);

	cout << "the lower bound points to: " << *ret.first << endl;   // >= val
	cout << "the upper bound points to: " << *ret.second << endl;  // > val
}

运行效果:

multiset的使用:

 multiset的用法和set相似,同样也是key/value不可被修改,multiset和set的区别在于:

multiset可以插入多个相同的key/value,即在multiset中可以存在多个某个key/value

set只允许唯一的key/value存在,一旦某个key/value已经存在那么就不会再插入相同值的key/value

insert:

erase:

 

返回删除某个值的个数 

删除一段区间的元素 

 find:

如果用find查找某个key/value,当此key/value存在多个,则find返回中序第一个val位置的迭代器

count:

multiset允许存在多个相同值,count可以统计某个值的个数

 equal_range:

第一个iterator:第一个>=val值位置的迭代器

第二个iterator:第一个>val值位置的迭代器

左闭右开区间

测试4:
void test_set4()
{
	multiset<int> s;
	s.insert(4);
	s.insert(3);
	s.insert(8);
	s.insert(2);
	s.insert(4);
	s.insert(5);
	s.insert(8);
	s.insert(2);
	multiset<int>::iterator it = s.begin();
	while (it != s.end())
	{
		//*it = 10;//不可以修改key/value
		cout << *it << " ";
		++it;
	}
	cout << endl;

	// 如果有多个值,find返回中序第一个value
	it = s.find(4);
	while (it != s.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;

	cout << s.count(2)<<endl;//统计某个value的个数

	// [>=value, >value)
	auto ret = s.equal_range(2);
	s.erase(ret.first, ret.second);//删除连续的value
	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;
}

运行效果:

map

map的介绍
 

key不可被修改,value可被修改

1 在map中,键值key通常用于排序和唯一地标识元素,而值value中存储与此键值key关联的内容

键值key和值value的类型可能不同,并且在map的内部,key与value通过成员类型value_type绑定在一起,为其取别名称为pair:
typedef pair<const key, T> value_type;
 

2 map中的元素总是按照键值key进行比较排序的

3 map中通过键值访问单个元素的速度通常比unordered_map容器慢

4 map支持下标访问符,即在[]中放入key,就可以找到与key对应的value

5 map通常被实现为平衡二叉搜索树(红黑树)


map的使用

key: 键值对中key的类型
T: 键值对中value的类型

insert:

 

注意:map的insert插入的是一个键值对

插入成功-> pair<新插入键值对所在节点的迭代器,true>

插入失败-> pair<已存在的键值对所在节点的迭代器,false>

再来熟悉一下键值对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)
{}
};

 pair的第二个构造函数非常强大,设计成为了模板

如果形参的U,V和正在被初始化的pair的两个成员的类型一致,则为拷贝构造

如果不是完全一致,则可视为构造,只要形参pair的两个成员可以赋值给正在被初始化的pair

make_pair函数:

make_pair会返回一个键值对,我们可以用此函数来构建理想的键值对

operator[]:(重要)

给定一个key, operator[]函数会返回与之对应的value的引用

上图简化版(只是大概示意图,不是正统语法):

 原理: operator[]函数会调用insert函数,其中的V()是value的类型的匿名对象,即使是内置类型也会有构造函数,所以若是value为int类型,那么插入的键值对,它的第二个成员的默认值就是0

insert返回一个键值对: 

所以operator[]有以下作用:

给定key返回对应value的引用,若是key不存在,则用默认value与key构造键值对然后插入

测试1:
void test_map1()
{
	map<string, string> dict;
	dict.insert(pair<string, string>("sort", "排序"));
	dict.insert(pair<string, string>("insert", "插入"));
	dict.insert(pair<const char*, const char*>("left", "左边"));
	dict.insert(make_pair("right", "右边"));//推荐这个
	string s1("xxx"), s2("yyy");
	dict.insert(make_pair(s1, s2));

	dict["erase"];  // 插入功能,原先无erase,并将对应的value初始化
	cout << dict["erase"] << endl; // 查找
	dict["erase"] = "删除"; // 修改
	cout << dict["erase"] << endl;// 查找
	dict["top"] = "顶级";  // 插入+修改
	dict["left"] = "剩余"; // 修改


	map<string, string>::iterator it = dict.begin();//迭代器遍历
	while (it != dict.end())
	{
		cout << it->first << ":" << it->second << endl;
		//cout << (*it).first << ":" << (*it).second << endl; //也可以选择这种方式打印
		++it;
	}
	cout << endl;

	for (auto& kv : dict)//范围for遍历+修改value(map的key不可被修改)
	{
		//kv.first += 'y';//不可以修改
		kv.second += 'y';//可以修改
		cout << kv.first << ":" << kv.second << endl;
	}
}

运行效果:

总结:

map中的的元素是键值对
map中的key是唯一的,并且不能修改
默认按照小于的方式对key进行比较
map中的元素如果用迭代器去遍历,可以得到一个有序的序列
map的底层为平衡搜索树(红黑树)
支持operator[]

multimap的介绍
 

存储键值对<key,value>,其中多个键值对之间的key是可以重复的
multimap和map的不同之处在于:map中的key是唯一的,而multimap中key是可以重复的
multimap中的接口可以参考map,功能都是类似的
 

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

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

相关文章

漫谈广告机制设计 | 万剑归宗:聊聊广告机制设计与收入提升的秘密(2)

书接上文漫谈广告机制设计 | 万剑归宗&#xff1a;聊聊广告机制设计与收入提升的秘密&#xff08;1&#xff09;&#xff0c;我们谈到流量作为一种有限资源&#xff0c;其分配方式&#xff08;或者交易方式&#xff09;也经历了几个阶段&#xff1a;第一个是谈判定价阶段&#…

新材料工厂生产管理mes系统

万界星空科技新材料云MES系统从需求分析、产品选型、系统集成、可扩展性和灵活性以及安全性和稳定性等多个角度进行考虑。 如果您的企业也属于新材料生产制造行业&#xff0c;同时也计划通过MES系统来进行整个生产过程的数字化管控。 欢迎搜索万界星空科技线上咨询或者直接拨…

论文阅读:JINA EMBEDDINGS: A Novel Set of High-Performance Sentence Embedding Models

Abstract JINA EMBEDINGS构成了一组高性能的句子嵌入模型&#xff0c;擅长将文本输入转换为数字表示&#xff0c;捕捉文本的语义。这些模型在密集检索和语义文本相似性等应用中表现出色。文章详细介绍了JINA EMBEDINGS的开发&#xff0c;从创建高质量的成对&#xff08;pairwi…

搭建网关服务器实现DHCP自动分配、HTTP服务和免密登录

目录 一. 实验要求 二. 实验准备 三. 实验过程 1. 网关服务器新建网卡并改为仅主机模式 2. 修改新建网卡IP配置文件并重启服务 3. 搭建网关服务器的dhcp服务 4. 修改server2网卡配置文件重启服务并效验 5. 设置主机1的网络连接为仅主机模式 6. 给server2和网关服务器之…

YOLOv4 学习记录

文章目录 整体概况数据增强Mosaic数据增强 基于CSPNet网络思想的架构改进Mish激活函数CSPNetCSPNet 3 大优势Partial Transition 层 CSPDarkNet (yolo v4 中的CSPDarkNet53) NeckSPPNetPAN-FPN 结构 正负样本匹配损失函数IOU 损失函数IOU的2个问题&#xff1a; GIOU Loss示意图…

力扣hot100 两数之和 哈希表

&#x1f468;‍&#x1f3eb; 力扣 两数之和 &#x1f60b; 思路 在一个数组中如何快速找到某一个数的互补数&#xff1a;哈希表 O(1)实现⭐ AC code class Solution {public int[] twoSum(int[] nums, int target){HashMap<Integer, Integer> map new HashMap<&g…

STM32CubeMX学习笔记(2)--DSP库的使用

1.DSP库简介 STM32的DSP库是为了支持数字信号处理应用而设计的&#xff0c;它包含了一系列优化的数学函数和算法&#xff0c;能够在STM32微控制器上高效地执行数字信号处理任务。 DSP库通常包括以下主要特性&#xff1a; 1.数学函数库&#xff1a; 包括各种基本的数学运算函数…

STM32电源名词解析

先来简单了解一下各种电源端口的命名 VCC&#xff1a;Ccircuit 表示电路的意思, 即接入电路的电压 VDD&#xff1a;Ddevice 表示器件的意思, 即器件内部的工作电压。 VSS&#xff1a;Sseries 表示公共连接的意思&#xff0c;通常指电路公共接地端电压。 GND&#xff1a;在电…

设计模式——责任链模式

文章目录 责任链模式的定义场景示例责任链模式实现方案责任链模式扩展责任链模式的优缺点责任链模式在框架源码中的应用 责任链模式的定义 责任链模式又称职责链模式&#xff0c;是一种行为型设计模式。官方描述&#xff1a;使多个对象都有机会处理请求&#xff0c;从而避免请…

Python 如何实现职责链设计模式?什么是职责链设计模式?Python 职责链设计模式示例代码

什么是职责链&#xff08;Chain of Responsibility&#xff09;设计模式&#xff1f; 职责链&#xff08;Chain of Responsibility&#xff09;设计模式是一种行为型设计模式&#xff0c;旨在构建一个对象链&#xff0c;每个对象都有机会处理请求&#xff0c;并且可以将请求传…

C++初阶 | [三] 类和对象(中)

摘要&#xff1a;类的6个默认成员函数&#xff0c;日期类 如果一个类中什么成员都没有&#xff0c;简称为空类。然而&#xff0c;空类并不是什么成员都没有&#xff0c;任何类在什么都不写时&#xff0c;编译器会自动生成6个默认成员函数。默认成员函数&#xff1a;用户没有显式…

python中列表的基础解释

列表&#xff1a; 一种可以存放多种类型数据的数据结构 列表的创建&#xff1a; 1.用【】创建列表 #创建一个空列表 list1[] #创建一个非空列表 list2 [zhang,li,ying,1,2,3] #输出内容及类型 print(list1,type(list1)) print(list2,type(list2))结果&#xff1a; 2.使用list…

《视觉SLAM十四讲》-- 回环检测

文章目录 10 回环检测10.1 概述10.1.1 回环检测的意义10.1.2 回环检测的方法10.1.3 准确率和召回率 10.2 词袋模型10.3 字典10.3.1 字典的结构10.3.2 实践&#xff1a;创建字典 10.4 相似度计算10.4.1 理论部分10.4.2 实践&#xff1a;相似度的计算 10.5 实验分析与评述 10 回环…

股票价格预测 | Python实现基于CNN卷积神经网络的股票预测模型(keras,Conv1D)

文章目录 效果一览文章概述源码设计参考资料效果一览 文章概述 股票价格预测 | Python实现基于CNN卷积神经网络的股票预测模型(keras) 源码设计 import quandl import datetimedf = quandl

FreeRTOS(教程非常详细)

概述&#xff1a; 之前写了关于FreeRTOS的部分内容&#xff0c;为了方便阅读&#xff0c;现在给汇总到一起了。全部学习完后&#xff0c;恭喜你对FreeRTOS有了更深的认知。 第一章 FreeRTOS移植到STM32 第二章 FreeRTOS创建任务 第三章 FreeRTOS任务管理 第四章 FreeRTOS消…

LeetCode【12】整数转罗马数字

题目&#xff1a; 思路&#xff1a; https://blog.csdn.net/m0_71120708/article/details/128769894 代码&#xff1a; public String intToRoman(int num) {String[] thousands new String[] {"", "M", "MM", "MMM"};String[] hun…

【自然语言处理】【大模型】赋予大模型使用工具的能力:Toolformer与ART

赋予大模型使用工具的能力&#xff1a;Toolformer与ART ​ 本文介绍两种赋予大模型使用外部工具能力的方法&#xff1a;Toolformer和ART。 Toolformer论文地址&#xff1a;https://arxiv.org/pdf/2302.04761.pdf ART论文地址&#xff1a;https://arxiv.org/pdf/2303.09014.pd…

【网络奇遇记】那年我与计算机网络的浅相知

&#x1f308;个人主页&#xff1a;聆风吟 &#x1f525;系列专栏&#xff1a;网络奇遇记、数据结构 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 一. 计算机网络的定义1.1 计算机早期的一个最简单的定义1.2 现阶段计算机网络的一个较好的定义 二. …

【IPC】消息队列

1、IPC对象 除了最原始的进程间通信方式信号、无名管道和有名管道外&#xff0c;还有三种进程间通信方式&#xff0c;这 三种方式称之为IPC对象 IPC对象分类&#xff1a;消息队列、共享内存、信号量(信号灯集) IPC对象也是在内核空间开辟区域&#xff0c;每一种IPC对象创建好…

【汇编】处理字符问题

文章目录 前言一、处理字符问题1.1 汇编语言如何处理字符1.2 asciiascii码是什么&#xff1f;ascii码表是什么&#xff1f; 1.3 汇编语言字符示例代码 二、大小写转换2.1 问题&#xff1a;对datasg中的字符串2.2 逻辑与和逻辑或2.3 程序&#xff1a;解决大小写转换的问题一个新…