C++进阶 | [4] map and set

news2024/12/24 21:26:49

摘要:set,multiset,map,multimap

前言

1. 容器 

  • 序列式容器:只存储数据,数据之间无关联关系。例如,vector、list、deque、……
  • 关联式容器:不仅存储数据,且数据之间有关联关系。例如,map、set、…

2. 键对值

用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量 key 和 valuekey 代表键值,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){}
};

本文将介绍 set、multiset、map、multimap 。 


1. set

set - C++ Reference (cplusplus.com)

set 是一个 key 模型的搜索二叉树。因此,set 对于数据具有排序(搜索二叉树的特点) + 去重(不允许重复值)的作用。
注意:set 内存储的数据不可被修改(BST都不支持修改key)


1)insert

//single element (1)    
pair<iterator,bool> insert (const value_type& val);

//with hint (2)    
iterator insert (iterator position, const value_type& val);

//range (3)    
template <class InputIterator>
void insert (InputIterator first, InputIterator last);

通过文档可以看到 insert 有 3 个重载。

当使用 pair<iterator,bool> insert (const value_type& val); 插入指定值的结点,函数返回的是一个 pair<iterator,bool> 的对象。该 pair 的 first 为迭代器,指向新插入的元素(插入成功 second 值为 true)或已有的等效元素(插入失败 second 值为 false)

使用示例:

#include<set>
#include<map>
#include<vector>
#include<iostream>

void test_set()
{
	std::set<int> s1;
	std::vector<int> vt = { 4,2,6,1,8,9,5,3,2,4 };
	for (auto e : vt)
	{
		auto tmp = s1.insert(e);
		std::cout << e << " " << tmp.second << std::endl;
	}
}

int main()
{
	test_set();
	return 0;
}

2)erase & find & count

(1)
     void erase (iterator position);

ps. position 必须是存在的,否则会报错

(2)
     size_type erase (const value_type& val);

ps.val 是否 是 存在的值都可以

(3)
     void erase (iterator first, iterator last);

由于 iterator position 不存在而报错的举例:

void test_set()
{
	std::set<int> s1;
	std::vector<int> vt = { 4,2,6,1,8,9,5,3,2,4 };
	for (auto e : vt)
	{
		auto tmp = s1.insert(e);
		std::cout << e << " " << tmp.second << std::endl;
	}

	std::set<int>::iterator it2 = s1.find(7);//没找都会返回s1.end()
	s1.erase(it2);//这样就会导致删除错误
	//因此,如果通过find函数找到结点再erase,那么使用erase之间要进行判断
}

  •  find count 的区别:
    iterator find (const value_type& val) const; 👉 find 返回类型是 iterator,判断是否 find 成功需要取到这个返回值,并判断是否与 std::set::end 相等。即 find 是都成功判断起来比较麻烦。
    
    size_type count (const value_type& val) const; 👉 (这里 size_type 参看文档可知是 size_t。)count 返回类型为 size_t,成功返回1,失败返回0,比较方便判断。

3)lower_bound & upper_bound

iterator lower_bound (const value_type& val) const;

Return value

An iterator to the the first element in the container which is not considered to go before* val, or set::end if all elements are considered to go before val.

Member types iterator and const_iterator are bidirectional iterator types pointing to elements.

*在这句话中,"go before" 表示在顺序上位于指定值 val 之前的意思。换句话说,如果元素被认为在指定值 val 之前,即比 val 小或者按照容器自身的排序规则排在 val 之前,那么这些元素就被视为"go before val"


iterator upper_bound (const value_type& val) const;

Return value

An iterator to the the first element in the container which is considered to go after* val, or set::end if no elements are considered to go after val.

Member types iterator and const_iterator are bidirectional iterator types pointing to elements.

*类比上面的 "go before",这句话中的 "go after" 就很好理解了。

void test_set2()
{
	std::set<int> myset;
	std::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);                     //       ^
													   // itloew将指向第一个不位于30之间的元素,即>=30,即30
	itup = myset.upper_bound(60);                      //                   ^
													   // itup将指向第一个位于60之后的元素,即>60,即70

	myset.erase(itlow, itup);                     // 10 20 70 80 90

	std::cout << "Myset Contains:";
	for (std::set<int>::iterator it = myset.begin(); it != myset.end(); ++it)
		std::cout << ' ' << *it;
}

对于上述代码,itlow = myset.lower_bound(30); == itlow = myset.lower_bound(25);  即这两句话得到的itlow是相等的。>=30即30;>=25即30.
而对于 myset.erase(itlow, itup); 即删除 [ 30, 60 ] 这个闭区间的所有值。


4)equal_range

pair<iterator,iterator> equal_range (const value_type& val) const;

Return value

The function returns a pair, whose member pair::first is the lower bound of the range (the same as lower_bound), and pair::second is the upper bound (the same as upper_bound).

如上,即 pair::first 为 按顺序第一个 >= val 的结点的 iterator,pair::second 为 按顺序第一个 > val 的结点的 iterator.
(ps.这个函数对 set 容器来说用处不大)


2. multiset

multiset - C++ Reference (cplusplus.com)

相比与 setmultiset 允许重复值。因此,multiset 对于数据仅具有排序的作用。multiset 与 set 很相似,以下简化表达,且只讲解一些存在差异的地方。

①对于重复值,插入到右树还是左树都可以。因为插入之后导致搜索二叉树不平衡会旋转,图例如下;

②如果有重复值,find(val) 会返回中序遍历序列的第一个值为 val 的 iterator;

equal_range(val) → 返回值 pair::first >= valpair::second > val →  [ first, second ) 在这个区间内,则找到了所有重复的 val 值结点;

count(val) 会统计值为 val 的结点个数;

erase(val) 删除所有值为 val 的结点,并返回删除结点的个数(return size_t)


3. map

map - C++ Reference (cplusplus.com)

map 是一个 KV 模型的搜索二叉树。KV 即 key and valuevaluekey 的映射值。key 不可被修改,value 可被修改。根据下表,KV的 K 即key_type,V即 mapped_type。KV 整体即 value_type。
(前面自己实现的 KV 模型的BST的 key 与 value 是分开的,而 map 的处理是将两者融合进 pair对象中。)

member typedefinition
key_typeThe first template parameter (Key)
mapped_typeThe second template parameter (T)
value_typepair<const key_type,mapped_type>

1)insert

single element (1)
pair<iterator,bool> insert (const value_type& val);
with hint (2)
iterator insert (iterator position, const value_type& val);
range (3)
template <class InputIterator>
  void insert (InputIterator first, InputIterator last);

value_type → pair<const key_type,mapped_type> → pair<const Key,T>

如下代码,Key → string,T → string. 

void test_map()
{
	std::map<std::string, std::string> dict;
	dict.insert(std::pair<std::string, std::string>("sort", "排序"));//方式一:匿名对象

	std::pair<std::string, std::string> pr("test", "测试");//方式二
	dict.insert(pr);

	pr = { "cruel","残忍的" };
	dict.insert(pr);

	auto it = dict.begin();
	while (it != dict.end())
	{
		std::cout << it->first << ":" << it->second << " ";
		++it;
	}
	std::cout << std::endl;
}
  • std::make_pair

对于 map 的 insert ,以下介绍一种更常用的写法。

std::make_pair:(function)<utility>

template <class T1, class T2>
  pair<T1,T2> make_pair (T1 x, T2 y);
//插入更常用的写法↓  方式三:make_pair()
dict.insert(std::make_pair("autumn","秋天"));

2)用 map 统计次(个)数

思路:对于一组给定的数据,实例化出相应的 map 对象,在 map<Type, int> 中依次查找给定的数据,该数据未在其(map实例化的对象)中则插入数据,若有则对其数量(int)++.

示例代码如下:

void test_Count()
{
	std::vector<std::string> vstr = { "apple","banana","grap","apple","cherry","cherry","grap","cherry","lemon","grap" };
	std::map<std::string, int> Count;
	for (auto str : vstr)
	{
		if (Count.find(str) == Count.end())//没找到
			Count.insert(std::make_pair(str, 1));
		else//找到了
			++Count.find(str)->second;
	}

	auto it = Count.begin();
	while (it != Count.end())
	{
		std::cout << it->first << ":" << it->second << std::endl;
		++it;
	}
}
  • ⭐ std::map::operator[]

mapped_type& operator[] (const key_type& k);

Access element

If k matches the key of an element in the container, the function returns a reference to its mapped value.

If k does not match the key of any element in the container, the function inserts a new element with that key and returns a reference to its mapped value. Notice that this always increases the container size by one, even if no mapped value is assigned to the element (the element is constructed using its default constructor).

A similar member function, map::at, has the same behavior when an element with the key exists, but throws an exception when it does not.

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

注意该函数的返回值:

Member type mapped_type is the type of the mapped values in the container, defined in map as an alias of its second template parameter (T) 

分析:

  1. 如上,通过阅读文档可知,[key] → 该操作有两种情况:①key已经存在,则返回key的映射值(mapped value)的引用;②key不存在,则插入key,并返回这个key的映射值的引用。
  2. A call to this function is equivalent to: (*((this->insert(make_pair( k,mapped_type() ))).first)).second
    逐步拆解这句代码👇

 

通过使用这个函数,下面进一步优化上面统计次(个)数的代码:

void test_Count2()
{
	std::vector<std::string> vstr = { "apple","banana","grap","apple","cherry","cherry","grap","cherry","lemon","grap" };
	std::map<std::string, int> Count;
	for (auto str : vstr)
	{
		++Count[str];//⭐
	}

	auto it = Count.begin();
	while (it != Count.end())
	{
		std::cout << it->first << ":" << it->second << std::endl;
		++it;
	}
}

4. multimap

multimap - C++ Reference (cplusplus.com)

  • 相比于 mapmultimap 允许重复值。
  • 不支持 operator[]

END

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

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

相关文章

Chrome谷歌浏览器如何打开不安全页面的禁止权限?

目录 一、背景二、如何打开不安全页面被禁止的权限&#xff1f;2.1 第一步&#xff0c;添加信任站点2.2 第二步&#xff0c;打开不安全页面的权限2.3 结果展示 一、背景 在开发过程中&#xff0c;由于测试环境没有配置 HTTPS 请求&#xff0c;所以谷歌浏览器的地址栏会有这样一…

《Python侦探手册:用正则表达式破译文本密码》

在这个信息爆炸的时代&#xff0c;每个人都需要一本侦探手册。阿佑今天将带你深入Python的正则表达式世界&#xff0c;教你如何像侦探一样&#xff0c;用代码破解文本中的每一个谜题。从基础的字符匹配到复杂的数据清洗&#xff0c;每一个技巧都足以让你在文本处理的领域中成为…

代码随想录——最大二叉树(Leetcode654)

题目链接 递归 二叉树 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val val; }* TreeNode(int val, TreeNode left, TreeNode rig…

Django Celery技术详解

文章目录 简介安装和配置创建并调度任务启动Celery Worker在视图中调用异步任务拓展功能 简介 Django Celery 是一个为Django应用程序提供异步任务处理能力的强大工具。它通过与消息代理&#xff08;如RabbitMQ、Redis&#xff09;集成&#xff0c;可以轻松地处理需要长时间运…

[C#]winform部署官方yolov10目标检测的onnx模型

【框架地址】 https://github.com/THU-MIG/yolov10 【算法介绍】 今天为大家介绍的是 YOLOv10&#xff0c;这是由清华大学研究团队最新提出的&#xff0c;同样遵循 YOLO 系列设计原则&#xff0c;致力于打造实时端到端的高性能目标检测器。 方法 创新 双标签分配策略 众所…

shell脚本-函数

一、函数 1.函数的定义和格式 函数定义&#xff1a;封装的可重复利用的具有特定功能的代码 先定义函数&#xff0c;再调用函数&#xff0c;注意顺序 函数类似于命令的别名&#xff0c;别名一些简单的小命令 函数是某一个脚本的别名&#xff0c;有些脚本会重复使用 函数格…

【链表】Leetcode 92. 反转链表 II【中等】

反转链表 II 给你单链表的头指针 head 和两个整数 left 和 right &#xff0c;其中 left < right 请你反转从位置 left 到位置 right 的链表节点&#xff0c;返回 反转后的链表 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], left 2, right 4 输出&#x…

【一刷《剑指Offer》】面试题 24:二叉搜索树的后序遍历系列

力扣对应题目链接&#xff1a;LCR 152. 验证二叉搜索树的后序遍历序列 - 力扣&#xff08;LeetCode&#xff09; 牛客对应题目链接&#xff1a;二叉搜索树的后序遍历序列_牛客题霸_牛客网 (nowcoder.com) 核心考点 &#xff1a; BST 特征的理解。 一、《剑指Offer》对应内容 二…

NASA数据集——严格校准的臭氧(O3)、甲醛(HCHO)、二氧化碳(CO2)和甲烷(CH4)混合比,以及包括三维风在内的气象数据

Alpha Jet Atmopsheric eXperiment Meteorological Measurement System (MMS) Data 阿尔法喷气式大气实验气象测量系统&#xff08;MMS&#xff09;数据 简介 Alpha Jet Atmospheric eXperiment (AJAX) 是美国国家航空航天局艾姆斯研究中心与 H211, L.L.C. 公司的合作项目&a…

LAMP网络服务架构

目录 LAMP 网站服务架构 LAMP的组成部分 LAMP的构建顺序 安装论坛 0.电脑已编译安装Apache&#xff0c;MySQL&#xff0c;PHP 1.创建数据库&#xff0c;并进行授权 2.上传论坛压缩包到 /opt ,并解压 3.上传站点更新包 4.更改论坛目录的属主 5.浏览器访问验证 LAMP 网…

2024年03月 Python(四级)真题解析#中国电子学会#全国青少年软件编程等级考试

Python等级考试(1~6级)全部真题・点这里 一、单选题(共25题,共50分) 第1题 运行如下代码,若输入整数3,则最终输出的结果为?( ) def f(x):if x==1:s=1else:s

各种情况下的线缆大小选择

开口线鼻子和导线对应大小 开口铜鼻子对应线径大小 变压器容量对应高压侧电流大小 开关电流线缆功率对照表 家庭/工业最常用电线铜线电流承载功率 电工常用名词对应符号 导线面积承载的安全载流量及允许负荷对照表 漏电保护器选择参考表 电动机功率换算电流 电机功…

应用程序中的会话管理和Cookie安全指南

应用程序中的会话管理和Cookie安全指南 在现代应用程序中&#xff0c;会话管理和Cookie安全是确保用户信息和数据安全的重要组成部分。本文将详细介绍会话管理的最佳实践以及如何通过安全的Cookie设置来保护会话ID的交换。 单点登录&#xff08;SSO&#xff09;及会话管理机制…

其二:使用递归法实现二分搜索

开篇 本文主要是利用递归法来实现一个简单的二分搜索程序。题目来源是《编程珠玑》第4章课后习题3。 问题概要 编写并验证一个递归的二分搜索程序, 并返回t在数组x[0…n-1]中第一次出现的位置。 思路分析 本题的思路与第一版相似&#xff0c;不过不同的是&#xff0c;为确保返回…

Android 通过布局生成图片

通过布局生成图片 首先效果图 在竖屏的情况下通过&#xff0c;一般情况下&#xff0c;只要布局在页面上可见&#xff0c;并显示全&#xff0c;通过布局生成图片&#xff0c;都可以&#xff0c;但是横屏就不行了&#xff0c;会出现图片显示不完全的情况。 val bitmap Bitmap.c…

KingbaseES数据库物理备份还原sys_rman

数据库版本&#xff1a;KingbaseES V008R006C008B0014 简介 sys_rman 是 KingbaseES 数据库中重要的物理备份还原工具&#xff0c;支持不同类型的全量备份、差异备份、增量备份&#xff0c;保证数据库在遇到故障时及时使用 sys_rman 来恢复到数据库先前状态。 文章目录如下 1.…

Laravel和ThinkPHP框架比较

一、开发体验与易用性比较 1. 代码可读性&#xff1a; - Laravel以其优雅的语法和良好的代码结构著称&#xff0c;使得代码更加易读易懂。 - 相比之下&#xff0c;ThinkPHP的代码可读性较为一般&#xff0c;在一些复杂业务场景下&#xff0c;可能会稍显混乱。 让您能够一站式…

【leetcode 141】环形链表——快慢指针(龟兔赛跑)

给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置&#xff08;…

浙江大学数据结构MOOC-课后习题-第六讲-图2 Saving James Bond - Easy Version

题目汇总 浙江大学数据结构MOOC-课后习题-拼题A-代码分享-2024 题目描述 测试点 思路分享 ①解题思路概览 我的想法是&#xff0c;先建立一个图&#xff0c;然后再利用DFS或者BFS来遍历判断当前顶点能否跳到岸上去 ②怎么建图&#xff1f; 首先要考虑采用什么数据结构来存储图…

计算机网络导论

网络结构的演变 网状结构 最开始的网络&#xff0c;主机之间都是两两相连 好处 这样连接&#xff0c;好处是安全性比较高&#xff08;A与B之间的连线断了&#xff0c;可以绕一下C&#xff09;&#xff1b; 另外通信不需要互相等待&#xff08;没有中间交换设备&#xff0c;所…