map和set的介绍和使用

map和set

关联式容器

我们在之前讲过STL的一些基础容器,例如vector,list,deque,forward_list等

这些其实统一都称为序列式容器,因为其底层都是线性的序列数据结构,而且存储的内容是元素本身

关联式容器也是存储数据的容器,不同的是,里面存储的是<key,value>的键值对,类似于我们之前讲的二叉搜索树的KV模型

键值对

键值对是我们用来表示一一对应关系的结构,包含key和value两个成员变量

key表示关键字,类似于字典中的单词,value表示具体的值,也就是字典中对应的具体释义

在C++中使用pair表示一对值,但并没有具体的对应关系,只是将这一对值进行了封装,可以读取和写入,当然pair也有一些非常有意思的内容,当我们观察其源码时可以看出

这里给出SGI-STL对pair的定义

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

介绍

set的文档

set直接翻译成中文是集合,而他与数学意义上的集合也有不同的地方,set是要求有序的,其次set中的元素不能被修改,元素是const的,但是允许插入删除

set的有序是可以自行定义升序或者降序的,默认是按照小于排序(升序),不允许重复值

set容器通过key访问单个元素的速度比unordered_set慢,但是都允许根据顺序对子集直接迭代

set在底层是使用二叉搜索树的红黑树实现的

set的底层实际上也是有pair的,只不过是<value,value>的形式,在插入元素时,只需要插入value即可

set查找的时间复杂度是 log ⁡ 2 n \log_2n log2n

模板参数

屏幕截图 2024-03-13 172738.png

第一行的T是存放元素的类型,实际是存在底层的<value,value>键值对

第二行的Compare是仿函数,用于确定是升序还是降序,默认为升序

第三行是一个空间配置器

这里其他的内容参考set的官方文档即可

map

介绍

map文档

map是关联容器,直接翻译称为映射,是我们之前讲的二叉搜索树的KV模型,他存储的元素是一个有key和value构成的有序对

在map中,key是唯一的,用于标识value

STL中使用typedef来减少长度

typedef pair<const key, T> value_type;

map内部是对key值排序,默认是升序,他对单个元素的访问速度比unordered_map慢,但是map允许根据顺序对元素进行直接迭代

map支持下标访问,可以直接找到与key对应的value,这里的实现让人赞叹

map的底层是由红黑树实现的,我们在之后的内容里也会使用红黑树实现set和map

模板参数

image.png

Key是键值对中的key,T对应的是value,后面分别是仿函数和空间配置器

需要注意的是,这里的map::key_type和map::mapped_type是typedef出的

image.png

这里我们注意到一个细节,在定义pair的时候,first被const了,说明key值是不能被修改的

为什么map支持下标访问

我们看map对方括号的重定义

image.png

image.png

也就是说他内部是这样实现的

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

这里看上去比较复杂,我们剥洋葱一样的来看

第一层是调用了map的insert插入函数,我们来看insert的定义

image.png

这里调用的是单参数的insert,value_type是一个pair对象,我们可以通过make_pair的名称就知道,他是用于构建pair对象的

insert的返回值是也一个pair对象,first是迭代器,bool是用来表示插入是否成功,如果成果,first指向的就是新pair,如果失败first指向的就是已经存在的pair

然后来看看make_pair函数的定义

image.png

这里就和我们设想的是一样的了,用于构建pair

然后我们看回去,他的参数有两个k和mapped_type(),这里的mapped_type实际上就是value的构造函数,因为在我们插入时只指定了key,没有value,因此直接调用value的构造函数即可

然后构造完成之后,返回的pair被插入到map中,返回值就是pair<iterator, bool>,这时我们取第一个iterator,表示指向插入的pair(无论是否成功插入,都会指向),然后再取第二个值,也就是插入之后的pair的value

返回值也就是pair之中的value

这里有个细节,重定义的返回值是引用的,说明可以支持赋值操作,初始化操作等

例如

map<string, string> m;
m["加"] = "plus";
m["减"] = "sub";
m["加"] = "add";
m["乘"];

总结一下就是分四步

  1. 用<key,value_type()>构建一个键值对,调用inset()插入到map中
  2. 如果key存在,插入失败,返回key所在位置的迭代器
  3. 如果key不存在,插入成功,返回新插入元素位置的迭代器
  4. 返回插入的键值对的引用

multiset

介绍

multiset文档

multiset与set类似,其中的元素是可以重复的,他的底层也是红黑树

红黑树是二叉搜索树,我们可以先按照二叉搜索树理解,他为什么也可以有序呢

实际上是因为他的插入规则是确定的,例如小于在左子树,大于等于在右子树,这样他的中序遍历就依然是有序的

multimap

multimap文档

multimap与map类似,需要注意的是,multimap不支持下标访问了,其他都是相同的

  • 22
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

栖林_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值