【C++/STL】:set和map的介绍及基本使用

news2024/11/23 11:40:37

目录

  • 前言
  • 一,树形结构的关联式容器
  • 二,set
    • 1,set 的介绍
    • 2,set 常用接口的使用
      • (1) set 的插入,迭代器遍历
      • (2) set 的区间构造,范围for
      • (3) set 的删除
  • 三,multiset
    • 1, multiset 的介绍
    • 2,multiset 的简单使用
  • 四,map
    • 1,map 的介绍
    • 2,map 常用接口的使用
      • (1) map 的构造
      • (2) map 的迭代器和范围 for
    • 3,map 中的下标访问符 [ ]
      • (1),下标访问符 [ ] 的多种功能
      • (2),统计字符串个数示例
  • 五,multimap
    • 1,multimap 的介绍
    • 2,multimap 的简单使用

前言

在前面,我们已经接触过STL中的部分容器,比如:vector、list、deque等,这些容器统称为序列式容器,因为其底层为线性序列的数据结构里面存储的是元素本身。那什么是关联式容器?它与序列式容器有什么区别?

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

一,树形结构的关联式容器

根据应用场景的不同,STL总共实现了两种不同结构的管理式容器:树型结构与哈希结构。树型结构的关联式容器主要有四种:map、set、multimap、multiset。这四种容器的共同点是:使用平衡搜索树(即红黑树)作为其底层结果,容器中的元素是一个有序的序列。下面一依次介绍每一个容器。

二,set

1,set 的介绍

(1) set是按照一定次序存储元素的容器
(2) 在set中,元素的value也标识它(value就是key,类型为T),并且每个value必须是唯一的set中的元素不能在容器中修改(元素总是const),但是可以从容器中插入或删除它们。
(3) set在底层是用二叉搜索树(红黑树) 实现的。

注意:
(1) set中的元素不可以重复(因此可以使用set进行去重)。
(2) 使用set的迭代器遍历set中的元素,可以得到有序序列。
(3) set中的元素默认排升序
(4) set中查找某个元素,时间复杂度为: l o g 2 n log_2 n log2n

2,set 常用接口的使用

使用set容器要包含头文件

#include <set>

在这里插入图片描述

set 常用接口的使用举例

(1) set 的插入,迭代器遍历

功能:排序+去重

void test_set1()
{
	//K模型搜索
	//排序+去重

	//插入
	set<int> s1;
	s1.insert(1);
	s1.insert(6);
	s1.insert(4);
	s1.insert(1);
	s1.insert(14);
	s1.insert(2);
	s1.insert(5);

	set<int>::iterator it = s1.begin();
	while (it != s1.end())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;
}

在这里插入图片描述

(2) set 的区间构造,范围for

void test_set2()
{
	//区间构造
	vector<int> v = { 2,8,4,6,3,9,2,4,5 };
	set<int> s2(v.begin(), v.end());

	//范围for
	for (auto e : s2)
		cout << e << " ";
}

在这里插入图片描述

(3) set 的删除

void test_set3()
{
	set<int> s3 = { 6,9,2,7,3,4,7,8 };
	for (auto e : s3)
		cout << e << " ";

	cout << endl;

	//删除
	s3.erase(8);
	for (auto e : s3)
		cout << e << " ";

	cout << endl;
}

在这里插入图片描述

三,multiset

1, multiset 的介绍

multiset 与 set 的内容介绍,功能和函数接口基本相同。

set的区别是:multiset中的value元素可以重复,set是中value是唯一的

2,multiset 的简单使用

此处只简单演示set与multiset的不同,其他接口接口与set相同。

void test_set2()
{
	//K模型搜索
	//排序 不去重,允许冗余

	//插入
	multiset<int> s1;
	s1.insert(1);
	s1.insert(6);
	s1.insert(4);
	s1.insert(1);
	s1.insert(14);
	s1.insert(2);
	s1.insert(1);
	s1.insert(5);

	multiset<int>::iterator it = s1.begin();
	while (it != s1.end())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;
}

在这里插入图片描述

四,map

1,map 的介绍

(1) map是关联容器,它按照特定的次序(按照key来比较)存储由键值key和值value组合而成的元素
(2) 在map中,键值key通常用于排序和惟一地标识元素,而值value中存储与此键值key关联的内容键值key和值value的类型可能不同
(3) 在内部,map中的元素总是按照键值key进行比较排序的。
(4) map支持下标访问符(重点),即在[]中放入key,就可以找到与key对应value。
(5) map通常被实现为二叉搜索树(更准确的说:平衡二叉搜索树(红黑树))。

2,map 常用接口的使用

使用 map 需要包含头文件:

#include <map>

在这里插入图片描述

(1) map 的构造

map 的构造有多种方式,最常用并且最喜欢用的是方式4(因为简短)

void test_map1()
{
	map<string, string> dict;
	
	// 1.有名对象
	pair<string, string> kv1("sort", "排序");
	dict.insert(kv1);

	// 2.匿名对象
	dict.insert(pair<string, string>("left", "左边"));

	// 3.函数模版
	dict.insert(make_pair("right", "右边"));

	// 4.多参数构造函数的隐式类型转换
	//pair<string, string> kv2 = { "string","字符串" };
	dict.insert({ "string","字符串" });

	// 5.initializer_list构造
	map<string, string> dict2 = { { "left", "左边" } ,{ "string","字符串" } ,{"right", "右边"} };
}

(2) map 的迭代器和范围 for

a,普通迭代器 iterator,key不能修改 value可以修改
const迭代器 const_iterator,key不能修改 value不能修改

b,范围for遍历,要加引用&

void test_map2()
{
	map<string, string> dict;
	
	//有名对象
	pair<string, string> kv1("sort", "排序");
	dict.insert(kv1);

	//匿名对象
	dict.insert(pair<string, string>("left", "左边"));

	//函数模版
	dict.insert(make_pair("right", "右边"));

	//多参数构造函数的隐式类型转换
	//pair<string, string> kv2 = { "string","字符串" };
	dict.insert({ "string","字符串" });

	//initializer_list构造
	map<string, string> dict2 = { { "left", "左边" } ,{ "string","字符串" } ,{"right", "右边"} };

	//迭代器遍历
	map<string, string>::iterator it = dict2.begin();
	while (it != dict2.end())
	{
		//it->first += 'x'; //err
		//it->second += "x"; //ok

		//cout << (*it).first << ":" << (*it).second << endl;
		cout << it->first << ":" << it->second << endl;
		//cout << it.operator->()->first << ":" << it.operator->()->second << endl;

		it++;
	}
	cout << endl;

	//范围for遍历,要加引用
	//本质:是把迭代器中 *it 赋值给 kv
	for (const auto& kv : dict2)
		cout << kv.first << ":" << kv.second << endl;

	cout << endl;
}

在这里插入图片描述

3,map 中的下标访问符 [ ]

首先来看看map中成员函数 operator[] 的简化实现:

V& operator[](const k& key)
	return (*((this->insert(make_pair(k, mapped_type()))).first)).second;

为了避免大家看的头晕,上面两行代码的分步解析:

V& operator[](const K& key)
{
	pair<iterator, bool> ret = this->insert(make_pair(key, V()));
	
	//不管插入成功还是失败,返回的都是key节点的迭代器,新插入的或是已存在的
	iterator it = ret.first;
	return it->second;
}

由上面的代码可得出:
(1) operator[]:给的是key,返回key对应的value的引用
(2) key存在,插入失败,返回 --> pair<存在的key所在节点的迭代器, false>
(3) key不存在,插入成功,返回 --> pair<新插入key所在节点的迭代器, true>

所以不管插入成功还是失败,返回的都是key节点的迭代器,新插入的或是已存在的

(1),下标访问符 [ ] 的多种功能

void test_map3()
{
	map<string, string> dict;
	dict.insert({ "string","字符串" });

	//插入(一般不这么用)
	dict["right"];

	//插入+修改
	//operator[]返回的是value的引用,进行修改
	dict["left"] = "左边";

	//查找
	cout << dict["string"] << endl;

	//修改
	dict["right"] = "右边";

	//成员函数count的使用:返回 key 的个数
	//在这里可以判断字符串在不在
	string str;
	cin >> str;
	if (dict.count(str))
		cout << "在" << endl;
	else
		cout << "不在" << endl;

}

通过监视窗口观察如下:

在这里插入图片描述

(2),统计字符串个数示例

方式1:
先查找判断要插入的字符串在不在,若第一次出现,就要插入,否则 value 值要++,统计起来比较麻烦

void test_map2()
{
	//统计字符串个数
	string arr[] = { "西瓜", "西瓜", "苹果", "西瓜",  "西瓜","香蕉", "苹果","西瓜", "香蕉","草莓" };
	map<string, int> countMap;

	for (auto& kv : arr)
	{
		auto it = countMap.find(kv);
		if (it != countMap.end()) //前面出现过
			it->second++;
		else
			 //第一次出现
			countMap.insert({ kv, 1}); //隐式类型转换
	}

	for (const auto& kv : countMap)
		cout << kv.first << ":" << kv.second << endl;
	cout << endl;
}

注意:map 中元素的顺序是按 key 排序的,就是这里的 string,默认排升序。

!](https://i-blog.csdnimg.cn/direct/3bc044d672d84126856ebd65b75c59a5.png)

方式2:
直接用 operator[] 的特性进行统计,核心代码只要一句

void test_map2()
{
	//统计字符串个数
	string arr[] = { "西瓜", "西瓜", "苹果", "西瓜",  "西瓜","香蕉", "苹果","西瓜", "香蕉","草莓" };
	map<string, int> countMap;

	for (auto& kv : arr)
	{
		countMap[kv]++;
		// 插入第一个,key是苹果,不存在,插入成功,
		// 此时value是0,插入成功后返回value的引用再++就变成1了
	}
	
	for (const auto& kv : countMap)
		cout << kv.first << ":" << kv.second << endl;
	cout << endl;
}

在这里插入图片描述

五,multimap

1,multimap 的介绍

multimap 与 map 的内容介绍,功能和函数接口基本相同。

multimap和map的唯一不同就是:map中的key是唯一的,而multimap中key是可以重复的,multimap中没有重载operator[]操作符

2,multimap 的简单使用

此处只简单演示map与multimap的不同,其他接口接口与map相同。

比如我们要对上面的水果出现的次数进行排序,有重复值,要用multimap

void test_map2()
{
	string arr[] = { "西瓜", "西瓜", "苹果", "西瓜",  "西瓜","香蕉", "苹果","西瓜", "香蕉","草莓" };
	map<string, int> countMap;

	for (auto& kv : arr)
	{
		countMap[kv]++;
		//插入第一个,key是苹果,不存在,插入成功,
		// 此时value是0,插入成功后返回value的引用再++就变成1了

		//对次数排序,当有重复值时,要用multimap
		multimap<int, string> sortMap;
		for (auto& kv : countMap)
		{
			sortMap.insert({ kv.second, kv.first });
		}
		
		for (const auto& kv : sortMap)
			cout << kv.first << ":" << kv.second << endl;
		cout << endl;
}

在这里插入图片描述

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

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

相关文章

python:sympy 求解 y=arcsin(x)和y=arccos(x)的曲线交点坐标

python sympy 先求解 sin(x)cos(x) 首先&#xff0c;你需要导入SymPy库&#xff0c;然后使用symbols功能创建一个符号变量x&#xff0c;并用solve功能来求解方程。 from sympy import symbols, sin, cos, solve# 创建符号变量x x symbols(x) # 创建方程 sin(x) - cos(x) 0…

[web]-反序列化漏洞-easy入门

打开网站看到代码&#xff1a; <?php highlight_file(__FILE__); class easy{ public $cmd; public function __wakeup(){ system($this->cmd); } } unserialize($_GET[pop]); ?> 是一个简单的反序列化题目&#xff0c;在本地启动php_study,生成序列化字符串&…

RK3568笔记四十:设备树

若该文为原创文章&#xff0c;转载请注明原文出处。 一、介绍 设备树 (Device Tree) 的作用就是描述一个硬件平台的硬件资源&#xff0c;一般描述那些不能动态探测到的设备&#xff0c;可以被动态探测到的设备是不需要描述。 设备树可以被 bootloader(uboot) 传递到内核&#x…

论文复现:Predictive Control of Networked Multiagent Systems via Cloud Computing

Predictive Control of Networked Multiagent Systems via Cloud Computing论文复现 文章目录 Predictive Control of Networked Multiagent Systems via Cloud Computing论文复现论文摘要系统参数初始化系统模型观测器预测过程控制器设计系统的整体框图仿真结果 论文摘要 翻译…

巧用Vue3 composition api的计算属性实现扁平化tree连线

本示例节选自vue3最新开源组件实战教程大纲&#xff08;持续更新中&#xff09;的tree组件开发部分。将进一步把基于Vue3 composition api的computed计算属性特性应用到组件开发实战中&#xff0c;继续以最佳实践的方式呈现给大家。 下面我们要实现的是扁平化的dom结构所呈现的…

大模型面经

大模型知识 基础算法 机器学习 常见经典公式推导 LR手推、求导、梯度更新 SVM原形式、对偶形式 FM公式推导 GBDT手推 XGB推导 AUC计算 神经网络的反向传播 常见通用问题 评价指标 分类 结合混淆矩阵 准确率&#xff08;Accuracy&#xff09; 识别对了的正例&am…

Qt Style Sheets-入门

Qt 样式表是一种强大的机制&#xff0c;允许您自定义小部件的外观&#xff0c;这是在通过子类化QStyle已经可行的基础上的补充。Qt 样式表的概念、术语和语法在很大程度上受到 HTML级联样式表 (CSS)的启发&#xff0c;但适用于小部件的世界。 概述 样式表是文本规范&#xff0…

SpringBoot增加网关服务

一、新建gateway项目 二、添加依赖 dependencies {implementation org.springframework.cloud:spring-cloud-starter-gateway:4.0.0 } 三、增加路由规则配置 一个web服务、一个service服务 bootstrap.yaml&#xff1a; server:port: 80 spring:application:name: gatewayc…

Java核心(六)多线程

线程并行的逻辑 一个线程问题 起手先来看一个线程问题&#xff1a; public class NumberExample {private int cnt 0;public void add() {cnt;}public int get() {return cnt;} }public static void main(String[] args) throws InterruptedException {final int threadSiz…

循环算法--整数反转

目录 一.前言 二.算法的核心原理 三.算法的核心代码及注释详解 一.前言 算法要求&#xff1a;给定一个整数n,要求对其中的数字进行反转。例如&#xff0c;当给定一个整数123的时候&#xff0c;反转的结果就为321。 二.算法的核心原理 通过仔细观察&#xff0c;我们不难发现&a…

扫描某个网段下存活的IP:fping

前言&#xff1a; 之前用arp统计过某网段下的ip&#xff0c;但是有可能统计不全。网络管理平台又不允许登录。想要知道当前的ip占用情况&#xff0c;可以使用fping fping命令类似于ping&#xff0c;但比ping更强大。与ping需要等待某一主机连接超时或发回反馈信息不同&#x…

非线性规划例题

求解非线性问题的函数&#xff1a; 操作步骤&#xff08;最优&#xff09;&#xff1a; 1、先试用蒙特卡洛模拟优先求出最优的初始值X0 2、使用函数&#xff1a;fincon求解最优解 clc,clear % 设置蒙特卡洛模拟的次数&#xff1a; n 10000000; fmin inf; x1 unifrnd(-10…

昇思MindSpore 应用学习-FCN图像语义分割-CSDN

日期 心得 昇思MindSpore 应用学习-FCN图像语义分割 (AI 代码解析) 全卷积网络&#xff08;Fully Convolutional Networks&#xff0c;FCN&#xff09;是UC Berkeley的Jonathan Long等人于2015年在Fully Convolutional Networks for Semantic Segmentation[1]一文中提出的用…

链表(4) ----跳表

跳表&#xff08;Skip List&#xff09;是一种随机化的数据结构&#xff0c;用于替代平衡树&#xff08;如 AVL 树或红黑树&#xff09;。它是基于多层链表的&#xff0c;每一层都是上一层的子集。跳表可以提供与平衡树相似的搜索性能&#xff0c;即在最坏情况下&#xff0c;搜…

JMX 反序列化漏洞

前言 前段时间看到普元 EOS Platform 爆了这个洞&#xff0c;Apache James&#xff0c;Kafka-UI 都爆了这几个洞&#xff0c;所以决定系统来学习一下这个漏洞点。 JMX 基础 JMX 前置知识 JMX&#xff08;Java Management Extensions&#xff0c;即 Java 管理扩展&#xff0…

verilog基础语法入门

文章目录 前言一、模块定义1. 模块声明2. 端口定义3. 信号类型声明4. 逻辑功能定义 二、运算符与表达式1. 算术运算符2. 逻辑运算符3. 位运算符4. 关系运算符5. 等式运算符6. 缩减运算符7. 移位运算符8. 条件运算符9. 位拼接运算符 三、语句1. 赋值语句2. 块语句3. 条件语句4. …

第1关 -- Linux 基础知识

闯关任务 完成SSH连接与端口映射并运行hello_world.py ​​​​ 可选任务 1 将Linux基础命令在开发机上完成一遍 可选任务 2 使用 VSCODE 远程连接开发机并创建一个conda环境 创建新的虚拟环境lm3 可选任务 3 创建并运行test.sh文件 参考文档 文档&#xff1a;https://g…

tcp协议下的socket函数

目录 1.socket函数 2.地址转换函数 1.字符串转in_addr的函数:​编辑 2.in_addr转字符串的函数&#xff1a;​编辑 1.关于inet_ntoa函数 3.listen函数 4.简单的Server模型 1.初步模型 1.sock函数和accept函数返回值的sockfd的区别 2.运行结果和127.0.0.1的意义 2.单进…

如何设计数据中心100G网络光纤布线

随着全球企业对带宽的需求呈指数级增长&#xff0c;数据中心需要升级以增强其计算、存储和网络能力。数据中心从10G/25G向100G迁移成为必然趋势。随着网络升级&#xff0c;数据中心的光纤布线系统也需要随之优化。本文将指导您如何设计数据中心100G网络光纤布线。 100G以太网的…

【LSTM和GRU极简,和最新的TT也就是状态】机器学习模型来学习状态

LSTM&#xff08;长短期记忆网络&#xff09;中的关键参数包括输入门、遗忘门、输出门、细胞状态和隐藏状态。以下是如何进行推理计算的示例&#xff1a; LSTM参数和公式 输入门&#xff08;i_t&#xff09;&#xff1a;决定输入的信息量。 遗忘门&#xff08;f_t&#xff0…