【C++】map和set

目录

关联式容器

特性 序列式容器 vector/list 关联式容器 map/set
顺序 插入顺序 key 排序
结构 线性排列 红黑树
查找 O (n) 慢 O (log n) 快
元素 单个值 key/key+value
排序 不会自动排 自动排序
用途 存数据、遍历 查找、映射、去重

序列式容器:map/set

STL总共实现了两种不同结构的管理式容器:树形结构和哈希结构。树形结构的关联式容器主要有四种:map、set、multimap、multiset 。共同点都是用平衡搜索树,即红黑树作为底层结构,容器中的元素是一个有序的序列

键值对

用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量key和value,key代表键值,value代表与key对应的信息。如英文单词和其中文含义就是一个一一对应的关系,就可以把英文单词当做key,中文含义当做value。

cpp 复制代码
//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) {}

};

pair中的first表示键值,second表示实值,即一一对应的关系。

构造一个匿名键值对pair对象,可以如下表示:

cpp 复制代码
pair<string, string>{"left","左边"};

库里面写了一个函数模板:make_pair ,作用就是:自动帮你创建一个 pair 对象。

如:

cpp 复制代码
make_pair("right","右边");

map -> key/value搜索树

对map的使用

cpp 复制代码
void Testkeyvalue3()//使用map
{
	map<string, string> dict;
	pair<string, string> kv1("hello","你好" );
	dict.insert(kv1);//insert插入的参数就是pair键值
	dict.insert(pair<string, string>{"left","左边"});//匿名对象
	dict.insert(make_pair("right","右边"));//使用make_pair(),实际是函数模板,即可不用指定传参类型
	//pair<string, string> kv2 = { "apple","苹果" };  多参数的构造函数支持隐式类型转换
    //dict.insert(kv2);这两行就分别是构造+拷贝构造
	dict.insert({ "apple","苹果" });//构造和拷贝构造优化为直接构造

	//会按key的大小进行插入

	//对map的遍历输出
	//auto it1 = dict.begin();
	//while (it1 != dict.end())
	//{
	//	//cout << (*it1).first << "->" << (*it1).second << endl;
	//	cout << it1->first << "->" << it1->second << endl;//常用
	//	it1++;
	//}

	string str;
	while (cin >> str)
	{
		auto s = dict.find(str);
		if (s != dict.end())//不等于相当于找到了str的位置,find找不到时返回的就是end迭代器
		{
			cout << str << "->" << s->second << endl;
		}
		else
		{
			cout << "无此单词,请重新输入" << endl;
		}
	}
}

迭代器重载了 *-> 运算符 ,所以可以直接当成指针来使用。
(*it1).first:*it1是对迭代器的解引用,

● .first:访问这个键值对的键

● .second:访问这个键值对的值
it1->first:-> 是指针访问成员运算符,it1->返回的是operator->,即pair *

相当于:(it1.operator->())->first

operator[]

形式:

cpp 复制代码
mapped_type& operator[] (const key_type& k);//即参数值是key,返回值是value

\]的功能等价于:![](https://i-blog.csdnimg.cn/direct/7d735ddd41e74972a3389d0fa644b5f2.png) 解释一下: 先看insert这块:![](https://i-blog.csdnimg.cn/direct/4ee9cea0a6b244f1b7b808b10926ba6c.png) mapped_type(),一个缺省值,不写的话相当于调用的是默认构造 insert的格式:![](https://i-blog.csdnimg.cn/direct/c370e553c5dd46b3949919ffc69b4884.png) 它的返回值是个pair,分为两种情况: 1. 当map中要插入一个`新的key`时,此时返回值就是`<新插入元素的迭代器,true>` 2. 当map中`已经存在一个key`时,此时返回值就是`` **insert返回的是pair,然后取first,即迭代器,进行解引用,即得到元素的\,再取second,所以\[\]的返回值就是value。** *** ** * ** *** 使用\[\]用于查找时要注意它是否存在,若它原本不存在则会变为插入。 ### multimap 它的key值可以重复,而map的key不能重复。 `multimap`中允许出现多个重复的键值,这就意味着`operator[]`**无法确认调用者的意图,也就不知道要返回哪个 键值 对应的 实值。** 所以`multimap`中没有提供 `operator[]` ## set -\> key搜索树 ### set的简单介绍 1. set是按照**一定次序存储**元素的容器。 2. set中的元素`不能在容器中修改`,元素总是const类型,但是可以从容器中插入或删除它们。 3. set中的元素总是会按照其内部类型所指示的特定严格弱排序准则进行排序。如对int类型就是升序,对string类型就是按字典序排序。 4. set中只存放value,但在底层实际存放的是由\构成的键值对。 5. set中查找某个元素的时间复杂度为O(log n) **迭代器遍历默认走的是中序遍历,会自动去重。** #### set的使用 对于set的各种函数,直接看文档即可:[set的文档](https://legacy.cplusplus.com/reference/set/set/) 简单说一下关于删除的: 删除掉最小值:s.erase(s.begin()); ```cpp for (int i = 1; i < 10; i++) myset.insert(i * 10); // 10 20 30 40 50 60 70 80 90 // [30, 60] // >= 30 itlow = myset.lower_bound(30); // // > 60 itup = myset.upper_bound(60); // myset.erase(itlow, itup); // 10 20 70 80 90 ``` 关于set的使用也很简单: ```cpp //前面要加上set的头文件 #include #include using namespace std; int main() { int arr[] = {1, 3, 2, 6, 7, 3, 0, 8, 7, 3, 1, 1}; set si(arr, arr+sizeof(arr)/sizeof(arr[0])); cout << si.size() << endl; //打印set中的元素 for(auto& e : si) cout << e << " "; //结果为:0 1 2 3 6 7 8,发现对其去了重,并进行了排序。 return 0; } ``` #### multiset multiset不会去重,在删除时,会把所有相同的值都删除。 multiset和set的区别: 1. find查找x时,多个x在树中,返回中序第一个x 2. 插入时,允许相等的值插入 ## 相关OJ题 以下几个题都可以用set或map实现。 [138. 随机链表的复制 - 力扣(LeetCode)](https://leetcode.cn/problems/copy-list-with-random-pointer/description/) 1. 处理深拷贝 2. 利用map构造原节点和拷贝节点之间的关系 问题点:新旧节点random的映射还有点懵逼。即对\[\]的使用还不熟练。 [142. 环形链表 II - 力扣(LeetCode)](https://leetcode.cn/problems/linked-list-cycle-ii/description/) [349. 两个数组的交集 - 力扣(LeetCode)](https://leetcode.cn/problems/intersection-of-two-arrays/description/) 法一:把两个数组都放入set中,小的++,相等的同时++; 法二:排序+去重,依次比较,小的++,相等的同时++; 应用:差集进行同步,交集进行比对 [692. 前K个高频单词 - 力扣(LeetCode)](https://leetcode.cn/problems/top-k-frequent-words/description/) 坑点:map对key进行排过序了,但是我如果直接用sort对value即次数进行排序,那就会乱,因为sort底层是快排,不稳定,可以用stable_sort,也可以调整仿函数的比较逻辑 *** ** * ** *** 感谢大家观看,如果大家喜欢,希望大家一键三连支持一下,如有表述不正确,也欢迎大家批评指正。 ![请添加图片描述](https://i-blog.csdnimg.cn/blog_migrate/315f2bf5c6b0982eb00881205b5db905.gif)

相关推荐
森G2 小时前
3.1、移植Qt程序到ARM平台----移植Qt程序到ARM平台(扩展)
arm开发·c++·qt
汀、人工智能2 小时前
[特殊字符] 第78课:乘积最大子数组
数据结构·算法·数据库架构·数组·前缀积·乘积最大子数组
tankeven2 小时前
HJ168 小红的字符串
c++·算法
白杆杆红伞伞2 小时前
Qt Event
开发语言·qt
Magic--2 小时前
Qt 桌面计算器项目
开发语言·qt
李昊哲小课2 小时前
Python办公自动化教程 - 第2章 单元格样式魔法 - 让表格变得美观专业
开发语言·python·excel·openpyxl
汀、人工智能2 小时前
[特殊字符] 第41课:翻转二叉树
数据结构·算法·数据库架构·图论·bfs·翻转二叉树
张健11564096482 小时前
QT创建线程
开发语言·qt
鲸渔2 小时前
【C++ 输入输出】cin、cout、cerr 与格式化输出
开发语言·c++·算法