C++:map和set的基本使用

news2024/11/25 23:15:03

文章目录

  • 搜索模型
  • 关联式容器
  • set
    • set的基本使用
    • set的其他使用
  • multiset
  • map
    • map的基本使用
    • map中的[]
  • multimap

搜索模型

在实际搜索中有两个搜索模型:Key的搜索模型和Key/Value的搜索模型

Key的搜索模型:

简单来说就是在一个搜索树,搜索树中的内容是一个一个的关键值,而通过一定的查找手段可以确定一个值在不在这个树内,在实际应用情境中可以在闸机,门禁等地方遇到这个搜索模型,通过给定的信息在已有的信息库中进行搜索,如果有就同一进入,如果没有就禁止进入

Key/Value的搜索模型:

这种搜索模型有两个功能,一个功能是进行搜索Key在不在这个搜索树内,第二个功能是用来通过Key可以查找Value的值,在实际应用情景中可以在字典,统计单词出现的次数中见到,在后面也会进行一些举例来更好的理解这种场景的意义所在

关联式容器

在前面的学习中有学到过不同的容器,例如有vector list deque等,这些容器被叫做是序列式容器,原因是因为它们底层的数据结构都是线性序列的数据结构,存储的是元素的本身

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

键值对:

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

set

对于set的定义解释:

Sets are containers that store unique elements following a specific order.

In a set, the value of an element also identifies it (the value is itself the key, of type T), and each value must be unique. The value of the elements in a set cannot be modified once in the container (the elements are always const), but they can be inserted or removed from the container.

Internally, the elements in a set are always sorted following a specific strict weak ordering criterion indicated by its internal comparison object (of type Compare).

set containers are generally slower than unordered_set containers to access individual elements by their key, but they allow the direct iteration on subsets based on their order.

Sets are typically implemented as binary search trees.

set是按照一定次序存储元素的容器,它的基本用法如下所展示:

set的基本使用

在这里插入图片描述
实现也是用模板来实现的,第一个模板参数是存储的元素类型,第二个是仿函数,第三个是空间配置器

set的基本使用

在这里插入图片描述
下面对于上面这些函数进行基本的实践和使用理解

void testset1()
{
	int arr[] = { 1,2,3,4,5,6,1,2,3,4 };
	set<int> st(arr, arr + sizeof(arr) / sizeof(arr[0]));
	for (auto e : st)
	{
		cout << e << " ";
	}
	cout << endl;
}

上面的样例构造了一个set,并将其中的内容进行了输出,输出结果是1 2 3 4 5 6,说明它包含了去重和排序的功能

insert的使用

在cplusplus中,对于insert的定义如下:

在这里插入图片描述
insert有三种用法,一种是直接插入一个值,在前文定义中提到value_type实际上是The first template parameter (T),也就是第一个模板参数,那么就默认可以把这个当成是set中存储的元素类型,也就是直接向set中插入一个元素,而函数的返回值是一个键值对,键值对中第一个数据是一个迭代器,第二个数据是布尔值,在文档中对于其定义如下:

The single element versions (1) return a pair, with its member pair::first set to an iterator pointing to either the newly inserted element or to the equivalent element already in the set. The pair::second element in the pair is set to true if a new element was inserted or false if an equivalent element already existed.

The versions with a hint (2) return an iterator pointing to either the newly inserted element or to the element that already had its same value in the set.

Member type iterator is a bidirectional iterator type that points to elements.
pair is a class template declared in (see pair).

简单来说就是,第一种版本的函数,其成员pair::first被设置为一个迭代器,该迭代器指向新插入的元素或集合中已经存在的等效元素。如果插入了新元素,则pair::中的第二个元素设为true;如果已经存在等效元素,则设为false

第二个版本的函数返回一个迭代器,该迭代器指向新插入的元素或在集合中已经具有相同值的元素

第三个版本的函数是通过迭代器来进行插入的

在这里插入图片描述
从测试的函数结果可以看出,和预期的结果是一样的,使用版本1的函数如果插入成功则pair的返回值是true,如果插入失败返回的是false,迭代器指向的位置就是插入元素的位置

find的使用和前面的STL容器基本相同,如果找到了返回该位置的迭代器,如果没找到返回end(),下面利用find函数来进行特定位置的插入

	// 在迭代器所指示的位置插入一个元素
	set<int>::iterator it3 = st.find(1);
	if (it3 != st.end())
	{
		st.insert(it3, 10);
	}

erase的用法:

在这里插入图片描述
erase函数版本1的参数时一个迭代器,返回值为空,版本2的参数是一个值,返回的值是删除元素的数量

void testset3()
{
	int arr[] = { 1,2,3,4,5,6 };
	set<int> st(arr, arr + sizeof(arr) / sizeof(arr[0]));

	for (auto e : st)
	{
		cout << e << " ";
	}
	cout << endl;

	set<int>::iterator it = st.find(2);
	if (it != st.end())
	{
		st.erase(it);
	}

	cout << st.erase(3) << endl;
}

set的其他使用

前面的使用在vector和list等序列式容器中其实也有这样的操作,总体来说大差不差,但是set是一个关联式容器,因此它是有一些前面没有见过的内容和操作的

lower_bound和upper_bound:

在这里插入图片描述
在这里插入图片描述
简单来说,这两个函数可以构造出一个迭代器区间,lower_bound返回的是第一个大于等于val值的位置,而upper_bound返回的是第一个大于val值的位置,因此可以用这个构造出一个迭代器区间,可以供给erase来使用

void testset4()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	set<int> st(arr, arr + sizeof(arr) / sizeof(arr[0]));

	for (auto e : st)
	{
		cout << e << " ";
	}
	cout << endl;

	set<int>::iterator lowit = st.lower_bound(2);
	set<int>::iterator upit = st.upper_bound(5);

	// 构造出要删除的区间是[2,5]
	st.erase(lowit, upit);

	for (auto e : st)
	{
		cout << e << " ";
	}
	cout << endl;
}

因此输出结果为

1 2 3 4 5 6 7 8 9 10
1 6 7 8 9 10

equal_range的使用:
在这里插入图片描述
获取相等元素的范围
返回一个范围的边界,该范围包括容器中与val等效的所有元素。

因为set容器中的所有元素都是唯一的,所以返回的范围最多只包含一个元素。

如果没有找到匹配项,则返回的范围长度为0,两个迭代器都指向容器内部比较对象(key_comp)认为在val之后的第一个元素。

如果容器的比较对象自反性地返回false(即,无论元素作为参数传递的顺序如何),则认为集合中的两个元素相等。

在这里插入图片描述

该函数返回一个pair,其成员pair::first是范围的下界(与lower_bound相同),pair::second是上界(与upper_bound相同)。

成员类型iterator和const_iterator是指向元素的双向迭代器类型。

// set::equal_elements
void testset5()
{
	std::set<int> myset;

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

	std::pair<std::set<int>::const_iterator, std::set<int>::const_iterator> ret;
	ret = myset.equal_range(30);

	std::cout << "the lower bound points to: " << *ret.first << '\n';
	std::cout << "the upper bound points to: " << *ret.second << '\n';
}

multiset

下面介绍的是multiset

在这里插入图片描述
对于这个容器来说,它是一个简单的排序的作用,并不会有去重的效果,如果有多个值,find返回中序第一个val,multiset在底层实际存储的是<int, int>的键值对,其他整体来说区别不算很大

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通常被实现为二叉搜索树(更准确的说:平衡二叉搜索树(红黑树))

在这里插入图片描述

从中看出,map中使用的就是Key_Value搜索模型,在传参的时候也需要传递两个参数

map的基本使用

insert的使用
在这里插入图片描述
结合上面的定义表可以看到,在map中的value_type实际上是一个键值对类型,也就是说在插入元素的时候每次要插入的都是一个键值对类型的元素,下面演示两种insert的插入方法

void testmap1()
{
	map<string, string> mp;
	
	// 1. 构造对象
	mp.insert(pair<string, string>("sort", "排序"));
	mp.insert(pair<string, string>("insert", "插入"));
	// 2. 函数调用
	mp.insert(make_pair("left", "左边"));
}

通常来说使用函数调用来构造一个pair对象更好一些

map中的[]

在序列式容器中,[]通常是用作运算符重载来看的,可以用于数据的随机存取,但是在map中并非如此,map中的[]的功能扩展很多:

在这里插入图片描述
下面用例子来说明map中[]的多种使用场景

在这里插入图片描述
在文档中有这样的一句话

A call to this function is equivalent to:
(*((this->insert(make_pair(k,mapped_type()))).first)).second

那么对这句进行解析:(*((this->insert(make_pair(k,mapped_type()))).first)).second

在理解这句前,要首先知道insert调用的结果是pair<iterator,bool> insert (const value_type& val),返回的是一个pair键值对,这里通过this指针调用了insert函数,再对所得到的键值对取它的first元素,也就是迭代器,再对迭代器进行解引用,迭代器指向的就是插入元素的位置,对迭代器的second解引用得到的就是Key_Value中的Value值

因此通过[]得到的返回值其实是通过Key来访问到Value值,如果没有Key会优先创建出Key的值,再对Value值进行一些访问修改等操作…

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

multimap

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

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

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

相关文章

大桌子安装笔记

单位弄了个服务器&#xff0c;里面全是虚拟机&#xff0c;自己也学着建了一个测试用的虚拟机&#xff0c;不知道干点啥好&#xff0c;朋友说做个网盘吧&#xff0c;就用大桌子。 于是&#xff0c;干起来&#xff0c;不会配制&#xff0c;就跟朋友一步一步学起来。 他说&#…

服务熔断保护实践--Sentinal

目录 概述 环境说明 步骤 Sentinel服务端 Sentinel客户端 依赖 在客户端配置sentinel参数 测试 保护规则设置 设置资源名 设置默认的熔断规则 RestTemplate的流控规则 Feign的流控规则 概述 微服务有很多互相调用的服务&#xff0c;构成一系列的调用链路&#xf…

LangChain介绍及代码实践

一、简介 LangChian 作为一个大语言模型开发框架&#xff0c;是 LLM 应用架构的重要一环。那什么是 LLM 应用架构呢&#xff1f;其实就是指基于语言模型的应用程序设计和开发的架构。 LangChian 可以将 LLM 模型、向量数据库、交互层 Prompt、外部知识、外部工具整合到一起&a…

如何看待将本增效?

如何看待将本增效&#xff1f; 么是降本增效&#xff1f;就是公司里&#xff0c;增进收益的动作要多做&#xff0c;无效的动作要少做&#xff0c;甚至不做。什么叫有效&#xff1f;回到公司的经营目标上去&#xff0c;企业的管理就是目标管理。降本&#xff0c;需要卓越运营&a…

NLP学习笔记:使用 Python 进行NLTK

一、说明 本文和接下来的几篇文章将介绍 Python NLTK 库。NLTK — 自然语言工具包 — NLTK 是一个强大的开源库&#xff0c;用于 NLP 的研究和开发。它内置了 50 多个文本语料库和词汇资源。它支持文本标记化、词性标记、词干提取、词形还原、命名实体提取、分割、分类、语义推…

【计算系统】5分钟了解超算,高性能计算,并行计算,分布式计算,网格计算,集群计算以及云计算的区别

5分钟了解超算&#xff0c;高性能计算&#xff0c;并行计算&#xff0c;分布式计算&#xff0c;网格计算&#xff0c;集群计算以及云计算的区别 1. 超算2. 高性能计算3. 并行计算4. 分布式计算5. 网格计算6. 集群计算7. 云计算小结相关资料 1. 超算 超级计算机&#xff08;Sup…

Android拖放startDragAndDrop拖拽onDrawShadow静态添加xml布局View,Kotlin(4)

Android拖放startDragAndDrop拖拽onDrawShadow静态添加xml布局View&#xff0c;Kotlin&#xff08;4&#xff09; import android.content.ClipData import android.graphics.Canvas import android.graphics.Point import android.os.Bundle import android.util.Log import a…

MATLAB 支持向量机(SVM)

MATLAB 支持向量机&#xff08;SVM&#xff09;详细解释&#xff08;含代码&#xff09; 基础线性可分最大间隔超平面 SVM分类基本代码和工具二分类线性非线性 多分类详细解释 基础 线性可分 简单来讲就是如何将两个数据用点、直线、平面分开。。。。。 二维空间中&#xff…

ios原生分享

什么是 ios 系统的原生分享呢&#xff0c;如下图所示 具体使用系统UIActivityViewController&#xff0c;完整代码如下&#xff1a; -(void)shareAny:(NSString *)text url:(NSString *)_url imagePath:(NSString *)_imagePath {NSLog("shareAny, text:%, url:%, imagePa…

Security ❀ DNS协议常见DOS攻击详解

文章目录 1. DNS协议基础概述2. DNS报文详解2.1. DNS Request 请求包2.2. DNS Reply 响应包 3. DNS Request Flood3.1. 攻击原理3.2. 防护方法3.2.1. TC源认证3.2.2. 被动防御3.2.3. CNAME防护模式3.2.4. *CANME类型解析过程** 4. DNS Reply Flood4.1. 攻击原理4.2. 防护方法 5…

【44.全排列Ⅱ】

目录 一、题目描述二、算法原理三、代码实现 一、题目描述 二、算法原理 三、代码实现 class Solution { public:vector<vector<int>> ret;vector<int> path;vector<bool> check;vector<vector<int>> permuteUnique(vector<int>&am…

C语言--温度转化(把华氏度转换为摄氏度)

一.问题描述: 有人用温度计测量出用华氏法表示的温度,今要求把它转换为以摄氏法表示的温度,转换公式如下: 这个代码是C语言的入门代码&#xff0c;难点在于5/9在程序中如何写出。在计算机中5/9等于1。 /符号&#xff1a;整除问题(整数/整数 结果是丢弃小数的整数) 5/2 2。那…

好看的个人导航页源码

这款导航页源码 非常合适个人使用 简洁漂亮 放点自己经常用到的网站 还支持别人自助添加快捷书签 源码获取&#xff1a;https://www.qqmu.com/930.html

UE5——网络——属性复制

当属性被注册进行复制后&#xff0c;您将无法再取消注册&#xff08;涉及到生存期这一话题&#xff09;。之所以会这样&#xff0c;是因为我们要预制尽可能多的信息&#xff0c;以便针对同一组属性将某一工作分担给多个连接。这样可以节省大量的计算时间。 virtual void GetLif…

java入坑之运行管理

一、概述 1.1Java开发和运行过程 编写阶段&#xff1a;采用各种编辑工具&#xff0c;编写.java文件编译阶段&#xff1a;采用javac.exe对java文件编译&#xff0c;产生.class文件运行阶段&#xff1a;采用java.exe加载.class文件运行 详细过程 1.2相关概念 javaOS管理 JavaOS是…

全新二开游戏支付通道/话费/电网、紫水晶带云端源码

源码修复可用&#xff0c;YY业务都可用 本店所售程序只供测试研究&#xff0c;不得使用于非法用途&#xff0c;不得违反国家法律&#xff0c;不得用于进行违法行为&#xff0c;否则后果自负&#xff01;购买以后用作他用附带的一切法律责任后果都由购买者承担于本店无任何关…

Linux开机、重启、关机和用户登录注销

1.【关机】 shutdown shutdown now 表示立即关机 shutdown -h now 表示立即关机 shutdown -h 1 表示1分钟后关机 halt 用来关闭正在运行的Linux操作系统 2.【重启】 shutdown -r now 表示立即重启 reboot 重启系统 sync …

蜜罐系统HFish的部署与功能实测

1. 引入 根据参考1对蜜罐的定义&#xff1a; 蜜罐&#xff08;Honeypot&#xff09;是一个计算机科学领域的术语&#xff0c;指用于检测或防御未经授权的行为或黑客攻击的陷阱。其名称来源于其工作原理类似于用来诱捕昆虫的蜜罐。蜜罐通常伪装成看似有利用价值的网路、资料、…

JVM修炼印记之初识

文章目录 JVM认识JVM的功能常见JVMHotSpot的发展历程 JVM认识 Java虚拟机&#xff08;Java Virtual Machine&#xff0c;JVM&#xff09;是一个用于执行Java字节码的虚拟计算机。它是Java语言的核心&#xff0c;可以在不同的操作系统和硬件平台上运行Java程序。 JVM负责将Java…

[架构之路-252/创业之路-83]:目标系统 - 纵向分层 - 企业信息化的呈现形态:常见企业信息化软件系统 - 企业应用信息系统集成

目录 第一章 什么是企业应用信息系统集成What 1.1 简介 1.2 架构 二、为什么需要企业应用信息系统集成Why 三、如何实现企业应用信息系统集成 3.1 步骤 3.2 企业应用集成的层次 3.3 业务流程重组 第一章 什么是企业应用信息系统集成What 1.1 简介 企业应用信息系统集…