【C++学习】map和set的使用

这篇具有很好参考价值的文章主要介绍了【C++学习】map和set的使用。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

🐱作者:一只大喵咪1201
🐱专栏:《C++学习》
🔥格言:你只管努力,剩下的交给时间!
【C++学习】map和set的使用

map和set的底层都是二叉搜索树,只是做了更进一步的限制,使其不会出现单只的情况,搜索的时间复杂度保证在O(log2N),具体的底层结构后面本喵再详细介绍,现在先来认识以下set和map

🌈关联式容器

首先要知道的是序列式容器,这种容器我们之前接触过,比如vector,list,deque等等。

序列式容器:

  • 底层为线性的数据结果(物理上或者逻辑上),容器中的元素储存的是元素本身。
  • 而且我们之前在使用序列式容器的时候,插入数据和删除数据只管操作就行,不用考虑其他因素。

关联式容器:

  • 存储的是<key,value>结构的键对值,在数据检索时比序列式容器效率更高。
  • 插入和删除数据时,要考虑该数据和它前后数据之间的关联性。

总的来说,关联式容器存放的数据不同,而且数据前后有一点的关联性。

⚡键对值

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

比如:现在要建立一个英汉互译的字典,那字典中就得右英文单词和与之对应的中文含义,而且它们的关系是一一对应的,此时用就可以使用键对值来存放,如<单词,汉语>。

在STL中,定义了一个键对值的类:

【C++学习】map和set的使用

  • 这个类的名字叫做pair,是一个模板类,可以存放任意类型的键对值,而且能够自定推演。
  • 它的成员变量右两个,分别是first和second,结构如:<first,second>。
  • 它也右自己的默认成员函数,和普通成员函数。

伪代码形式:

template <class T1, class T2>
struct pair
{
	typedef T1 first_type;
	typedef T2 seco_type;
	T1 first;
	T2 second;
	pair():first(T1()),second(T2()){}
	pair(const T1& a, const T2& b):first(a),second(b){}
};
  • 键对值注定是要在类外进行访问的,所以使用struct而不用class。

make_pair():

该函数是用来制作一个pair类型的匿名对象的:

pair<string, string>("string", "字符串");
make_pair("string", "字符串");

上面俩句代码是等价的,都是在创建一个pair类型的匿名对象,让你选择你会选择哪种方式呢?

  • make_pair()是为了让我们更加方便的使用键值对。

🌈set

【C++学习】map和set的使用
set和之前学习的容器一样,也是一个模板类,但是它的底层是关联式容器,也就是二叉搜索树,并且有很多的成员函数,这些接口相信大家大部分都不陌生。

  • set存放的数据只有一个,就是它本身。

⚡构造函数

【C++学习】map和set的使用

构造函数有三个,分别是默认构造函数、使用迭代器区间的构造函数、拷贝构造函数。

  • 因为底层是二叉搜索树,所有就会涉及到比较,构造函数参数就是比较方式,是一个仿函数,但是默认情况下是有缺省值的。

【C++学习】map和set的使用

  • 使用默认构造函数构造出来的s1是空的,里面什么都没有。
  • 使用迭代器区间构造出来的s2,里面是这段区间中的数据。
  • 拷贝构造函数构造出来的s3,内容和s2的完全一样。

set的去重功能:

上面使用迭代器区间构造s2的时候,原本的数组中有很多个1,但是构造出来的set中,只有一1。

  • set具有降重的功能,当插入的数据已经存在时就不会再插入,这一点在二叉搜索树中就讲解过。

【C++学习】map和set的使用
可以看到,数组中有多个重复数字,用这些数字构造出来的set,里面每个数字只存在一个,重复的都被去除了。

迭代器的中序移动:

在打印set中的数据时,我们发现打印出来的结果是升序的,在学习二叉搜索树的时候我们知道,采用中序遍历的方式打印出来的结果就是升序的。

  • 迭代器++时,移动的顺序就是中序遍历的顺序,所以使用迭代器遍历时得到的结果和中序遍历是一样的。

⚡增删查改

insert():

【C++学习】map和set的使用
插入函数insert有3个重载函数,其中第一个是插入一个数据,并且返回一个键对值,第二个是指定位置插入,返回插入的位置,第三个是插入一段迭代器区间。

【C++学习】map和set的使用

  • 在set中插入原本没有的数据50,插入成功,返回键对值中,迭代器指向新插入的位置,布尔值是1。
  • 在set中插入原本就存在的数据5,插入石板,返回键对值中,迭代器指向set中5的位置,布尔值是0。

强烈不建议使用指定位置插入

指定位置向set中插入数据,有可能会破环二叉搜索的结构,除非在插入之前能够确定不会破坏结构。一般情况下我们都不会指定位置插入。

【C++学习】map和set的使用

  • 迭代器区间中的数据全部插入到了set中。
  • set中原本就存在5,所以迭代器区间中的5不会再插入。

find():

【C++学习】map和set的使用

  • 根据指定的值在set中插入,如果存在则返回该值所在位置的迭代器,如果不存在,则返回set的结束位置的迭代器end()。

【C++学习】map和set的使用

  • 5存在于set中,返回该位置的迭代器。
  • 50不存在于set中,返回set的end迭代器。

还有一个接口函数可以代替find,该结构名为count():

【C++学习】map和set的使用

  • 返回指定数据的个数,如果不存在则返回0。

由于set具有降重功能,里面不会存在重复的数据,所以它在这里的功能是和find一样的,只是不过返回的是数字,而不是迭代器。

【C++学习】map和set的使用
存在时返回值是1,不存在时返回值是0。

erase():

【C++学习】map和set的使用
有三个重载函数,第一个删除指定迭代器位置的值,第二个返回删除指定值的个数,第三个删除迭代器区间中所有数据。

  • 第二个重载函数,由于set中没有重复值,所以返回的值就是1。

【C++学习】map和set的使用

  • 使用指定迭代器位置的erase时,需要先使用find找到。
  • 使用指定数据的erase时,删除成功返回1,如果不存在则返回0。
  • 使用迭代器区间的erase时,将区间内的数据全部删除。
  • 迭代器区间用的是set的迭代器区间。

修改:

在二叉搜索树的时候本喵就说过,不支持修改,因为很有可能会破环树的结构,同样的set也不支持修改。

获取上下边界:

【C++学习】map和set的使用
【C++学习】map和set的使用

  • 下边界给的数据是2时,返回的就是2的迭代器。
  • 上边界给的数据是7时,返回的是8的迭代器,也就是返回7的下一个数据所在位置的迭代器,因为C++中的迭代器都是左闭右开区间的。
  • 上边界给的数据是5时,返回的是6的迭代器,因为5不存在,所以返回它下一个数据的迭代器。
  • lower_boubder(val):返回的iterator >= val所在的位置的迭代器。
  • upper_bounder(val):返回的iterator > val所在的位置迭代器。

但是这两个接口用的非常少,仅了解就可以。

其他成员函数的使用,包括迭代器,我们在学习vector,list等容器时已经用的炉火纯青了,本喵就不再介绍了,还有一些很不常用的接口,再以后用到的时候再详细介绍。

🌈multiset

【C++学习】map和set的使用
multiset和set在同一个头文件中,而且几乎是一模一样的。

  • 区别在于multiset支持数据重复,而set不可以。

【C++学习】map和set的使用

  • 重复数据仍然可以插入到multiset中。
  • set:排序 + 降重
  • multiset:排序(不降重)

count():

在set中count成员函数和find功能类似,但是在multiset中它就有了它的作用。

【C++学习】map和set的使用

  • mutiset中有3个5,返回就是3。
  • multiset中没有50,返回就是0。

erase():

【C++学习】map和set的使用
erase中的第二个重载函数也是给multiset使用的。

【C++学习】map和set的使用

  • mutiset中有2个3,全部被删除,所以返回值就是2。
  • mutiset中没有30,所以返回值就是0。

find():

使用find查找multiset中的重复元素时,返回的是哪个呢?

【C++学习】map和set的使用

  • find找到的是中序遍历的第一个3。

multiset其他方面和set一模一样,本喵就不再介绍了。

🌈map

【C++学习】map和set的使用
map和set一样,也是一个关联式容器,底层是二叉搜索树。

  • map中存放的是键对值,如上图所示,有两个模板参数,这两个参数组成一对键对值。

⚡构造函数

【C++学习】map和set的使用

  • 没有使用一个键对值进行构造的构造函数,只有一个键对值时,只能先创建在使用insert插入。

【C++学习】map和set的使用

  • 使用默认构造函数创建的map是空的。
  • 插入键对值时,使用make_pair创建匿名对象更加方便。

【C++学习】map和set的使用

  • 使用迭代器区间进行初始化。
  • 拷贝构造初始化。

特性:

【C++学习】map和set的使用

  • map具有降重功能,和set一样。
  • 不能插入相同的键值对,和set一样,map不支持重复数据。
  • 不能插入key值相同,val值不同的键值对。
  • map中虽然存放的是键值对,但是它的判断逻辑都只看key值,也就是first所表示的变量。

map也具有排序 + 降重的功能,依据只看key值而不管value值。

⚡增删查改

insert():

【C++学习】map和set的使用
用法和set中的一样,只是map插入的是键值对。

【C++学习】map和set的使用

  • 插入一个键值对时,返回的也是一个键值对,返回的键值对中,first是插入键值对所在位置的迭代器,second是bool值,成功就返回1,失败就返回0。
  • 迭代器区间插入时,map已经有的元素就不再插入了。

同样强烈不建议使用指定位置插入

find():

【C++学习】map和set的使用

  • 查找时,只需要指定要查找键值对中的键值key就可以,find是根据key去搜索的。
  • 查找到以后返回键值对所在位置,没有找到返回end迭代器。

【C++学习】map和set的使用

  • 键值4存在,它的value值是李四,所以通过返回的迭代器可以找到。
  • 键值5不存在,所以返回map的end迭代器。

erase():

【C++学习】map和set的使用
和set中的使用情况一样,除了指定迭代器位置和迭代器区间外,只需要指定键值key就可以删除对应的键值对。

map和set一样,不支持修改,因为可能会破坏二叉搜索树的结构

  • 除了插入这样的增加操作时,需要一个键值对,其他操作都是根据键值对中的键值key来处理的。

⚡operator[]

现在使用map来统计KV模型例子中水果的个数:

void TestMap6()
{
	string arr[] = { "苹果", "西瓜", "香蕉", "草莓", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };
	map<string, int> countMap;
	for (auto& e : arr)
	{
		map<string, int>::iterator it = countMap.find(e);
		//map没有该水果,插入,数量为1
		if (it == countMap.end())
		{
			countMap.insert(make_pair(e,1));
		}
		//map中有该水果,数量加1
		else
		{
			it->second++;
		}
	}
	//查看map
	for (auto& e : countMap)
	{
		cout << e.first << ":" << e.second << endl;
	}
	cout << endl;
}

【C++学习】map和set的使用
成功统计出了水果的个数,此时水果名是key值,数量是value值。

还有一种非常不可思议的方式:

【C++学习】map和set的使用

  • 原本那么一大堆的判断逻辑,此时一句代码就搞定了。

要想知道原因,就必须了解operator[]成员函数。

【C++学习】map和set的使用

  • 键对值中的key值充当下标。

【C++学习】map和set的使用
文档中解释,调用operator[]相当于在调用上面那一句代码。可以看到这句代码非常长,得需要好好分析。

【C++学习】map和set的使用

这句代码可以这样解释,但是还是有些复杂。

Value& operator[](const K& key)
{
	//1.插入	2.查找
	pair<map<K, Value>::iterator, bool> ret = insert(make_pair(key, Value()));

	//3.修改
	return ret.first->second;
	}
  • 插入:使用insert进行了插入。
  • 查找:插入后返回的键对值中有布尔类型,插入就返回true,否则返回false。
  • 修改:最终的返回值是插入键对值中的value。

一个operator[]可以实现3个功能,所以可以代替最开始那一堆逻辑。

countMap[e]++;

这句代码是如何实现插入,查找,修改三个功能呢?

  • 首先:insert(e),map中如果不存在e,则插入,返回e的second的引用,也就是计数值。如果存在e,则不插入,直接返回e的second的引用。
  • 如果是新插入的e,此时e的second的引用是0,加加后变成了1。如果不是新插入的,对e的second的引用进行加加,数量也就被加加了。
  • 这里只是用到了operator[]的插入和修改功能,没有使用到查找。

🌈multimap

【C++学习】map和set的使用
multimap和map也是在一个头文件中,使用和map也一样,就像是multiset和set的关系。

  • multimap也是支持数据重复的,而map不可以。

【C++学习】map和set的使用

  • 重复数据仍然可以插入到multimap中,同样也只是看key值。
  • map:排序 + 降重
  • multimap:排序(不降重)

mutimap中没有operator[]

如果有它的话,operator[e]返回的second应该返回哪个呢?毕竟可以找到多个first,所以mutimap不提供operator[]成员函数。

insert():

【C++学习】map和set的使用

  • multimap的insert中,没有返回键对值的,返回的是插入键对值所在位置的迭代器。其他使用都一样。

map和set以及multiset和multimap的用法非常相似,可以相互参考。

🌈map和set在题目中的应用

⚡统计前K个高频单词

【C++学习】map和set的使用
思路分析:

  • 将字典放入到map中,统计每个单词的次数。
  • 再将键值对中的key值和value交换,并插入到一个vector中。
  • 使用sort按照key进行排序。
  • 然后将排序后vector中键值对的value(也就是字符串)插入到返回vector。

【C++学习】map和set的使用

  • 统计之后map中的数据形式,pair<“单词”,次数>。
  • 将pair<次数,“单词”>放入到vector中,此时key就成了次数,value成了单词。
  • 使用sort对vector中的数据进行排序。
  • 输出排序后vector中键值对的value,也就是单词。

【C++学习】map和set的使用
此时的结果"i"和"love"位置不对,这是因为sort采用的快排,快排是一个不稳定的算法,所以采用一个稳定算法就可以。

【C++学习】map和set的使用
算法库中提供了稳定的排序算法。

【C++学习】map和set的使用
但是此时函数不行,位置还是不对,这是什么原因呢?
【C++学习】map和set的使用
原因就在于pair类型中对大于号的重载:

【C++学习】map和set的使用

  • 库中对operator>()的重载中,主要取决于两个键值对中的key值。

所以需要我们在仿函数中指定更严格的比较方式:

【C++学习】map和set的使用

  • 当键值对中的first相等时,意味着这两个单词的个数相同。
  • 此时在仿函数中指定按照字典序排列。

【C++学习】map和set的使用
此时就成功了。

⚡求两个数组的交集

【C++学习】map和set的使用
思路分析:

  • 首先进行排序 + 去重,将两个数组放在两个set中。
  • 两个set中的数据同时进行比较,相等就是交集,输出到返回vector中,不相等时,小的set的迭代器继续向后移动。

【C++学习】map和set的使用
上边是思路的示意图。

【C++学习】map和set的使用

【C++学习】map和set的使用
上边代码可以成功通过。

🌈总结

map和set的使用相对于之前的容器来说确实有一点复杂,主要在一些接口上面。要知道set和multiset以及map和mutimap的区别。文章来源地址https://www.toymoban.com/news/detail-418563.html

到了这里,关于【C++学习】map和set的使用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C++:map和set的介绍及使用

    目录 1. 关联式容器 2. 键值对 3. 树形结构的关联式容器 3.1 set 3.1.1 set的介绍 3.1.2 set的使用 3.2 map 3.2.1 map的介绍 3.2.2 map的使用 3.3 multiset 3.3.1 multiset的介绍 3.3.2 multiset的使用 3.4 multimap 3.4.1 multimap的介绍 3.4.2 multimap的使用 在之前文章中,我们已经接触过STL中的部分容器,比如:

    2024年02月03日
    浏览(30)
  • 【C++】详解map和set基本接口及使用

    关联式容器也是用来存储数据的,但与序列式容器不同的是,关联式容器里面存储的是 key, value 结构的键值对,因此**在数据检索时比序列式容器效率更高**。 键值对是用来表示 具有一一对应关系的一种结构 ,该结构中一般只包含两个成员变量 – key 和 value;其中 key 代表键

    2024年02月08日
    浏览(33)
  • 【C++】map、set、multimap、multiset的介绍和使用

    我讨厌世俗,也耐得住孤独。 1. 之前所学的vector,list,deque等容器都是序列式容器,因为他们的底层数据结构都是线性的,并且数据结构中存储的都是元素数据本身,也就是单一的变量。 而下面所学的set、map、multimap、multiset等容器都是关联式容器,他们内部存储的不再是单

    2023年04月15日
    浏览(31)
  • 【C++】使用红黑树进行封装map和set

    🌇个人主页:平凡的小苏 📚学习格言:命运给你一个低的起点,是想看你精彩的翻盘,而不是让你自甘堕落,脚下的路虽然难走,但我还能走,比起向阳而生,我更想尝试逆风翻盘 。 🛸 C++专栏 : C++内功修炼基地 家人们更新不易,你们的👍点赞👍和⭐关注⭐真的对我真

    2024年02月07日
    浏览(30)
  • 【C++】STL——set/multiset 和 map/multimap的使用

    在初阶阶段,我们已经接触过STL中的部分容器 比如:vector、list、deque、forward_list(C++11)等,这些容器统称为 序列式容器 ,因为其底层为线性序列的数据结构,里面存储的是元素本身。 而今天我们要学习的几个容器称为关联式容器,那什么是关联式容器?它与序列式容器有什

    2024年02月14日
    浏览(31)
  • 【C++】unordered_set 和 unordered_map 使用 | 封装

    unordered_map官方文档 unordered_set 官方文档 set / map与unordered_set / unordered_map 使用功能基本相同,但是两者的底层结构不同 set/map底层是红黑树 unordered_map/unordered_set 底层是 哈希表 红黑树是一种搜索二叉树,搜索二叉树又称为排序二叉树,所以 迭代器遍历是有序的 而哈希表对应的

    2024年02月06日
    浏览(32)
  • 【C++】 使用红黑树模拟实现STL中的map与set

    前面的文章我们学习了红黑树,也提到了C++STL中的map和set的底层其实就是用的红黑树来实现的(而map和set的使用我们前面也学过了)。 既然红黑树我们也学习过了,那这篇文章我们就用红黑树来简单实现一下STL中的map和set,重点是学习它的框架。 上一篇文章我们实现了红黑

    2024年02月12日
    浏览(21)
  • 【C++】unordered_map和unordered_set的使用

    文章目录 前言 一、unordered_map的使用及性能测试 二、unordered_set的使用 1.习题练习 总结 unordered 系列关联式容器 : 在 C++98 中, STL 提供了底层为红黑树结构的一系列关联式容器,在查询时效率可达到O(logN) ,即最差情况下需要比较红黑树的高度次,当树中的节点非常多时,

    2024年02月06日
    浏览(36)
  • C++:stl中set(multiset)和map(multimap)的介绍和使用

    本文主要从概念、常用接口和使用方法方面介绍set(multiset)和map(multimap)。 目录 一、概念介绍 1.关联式容器 2.键值对 3. 树形结构的关联式容器 二、set和multiset 1.set的介绍 2.set使用 1. set模板参数列表 2. set构造 3. set迭代器 4. set容量 5. set修改操作 6.set使用举例 3.multiset介绍 4.mul

    2024年02月08日
    浏览(31)
  • C++进阶--unordered_set、unordered_map的介绍和使用

      在C++98中,STL提供了底层为红黑树结构的一系列关联式容器,在查询时效率可达到 l o g 2 N log_2N l o g 2 ​ N ,即最差情况下需要比较红黑树的高度次,当树中的节点非常多时,查询效率也不理想。最好的查询是,进行很少的比较次数就能够将元素找到,因此在C++11中,STL又

    2024年01月16日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包