C++ map/set源码封装简单分析

文章目录

  • 一. 问题的抛出
  • 二. 红黑树的实现
  • 三. map/set实现
  • 四. 分析
  • 五. KeyOfValue仿函数
  • 结束语

一. 问题的抛出

我们知道C++的STL中map和set的底层都是红黑树。
但是仔细思考一下,map是存储键值对,也就是Key_Value模型
而set是Key的模型
那么STL中的红黑树是如何实现适配这两种不同存储模型的。
我们从源码中,可以获取到我们想知道的答案

C++ map/set源码封装简单分析_第1张图片

二. 红黑树的实现

我们首先来看一下红黑树结点的实现吧
C++ map/set源码封装简单分析_第2张图片

可以看到STL中的红黑树结点的设计和我们学习的红黑树的结构大抵相同,只不过STL是使用bool值标记颜色
而且,红黑树的结点存储的只是Value
接下来,我们再看红黑树的类

C++ map/set源码封装简单分析_第3张图片

我们先了解一下模板参数

Key:Key值
Value:Value值
KeyOfValue:从Value值中分离出Key
Compare:比较器
Alloc:内存池

比较器和内存池和本章内容关系不大,我们不考虑
我们主要要关注前三个参数
同时,我们看到,内部有node结点,但是传入的模板参数是Value,也是一个值。


看到这里,我们发现,STL的红黑树好像没什么特别的,也是存储单值的二叉搜索树,但是map存储的明明是Key_Value,一对键值对,map是如何使用这棵红黑树的呢?

那么接下来,我们就来看一下map和set的源码

三. map/set实现

我们首先查看set的源码

C++ map/set源码封装简单分析_第4张图片
set的模板参数只有Key,但是我们看到Key被重命名成了两个属性,一个是key_type,一个是value_type,并且分别传入给了红黑树
红黑树的模板参数有一个Key,一个Value,但实际结点存储的只有Value。
接下来,我们将红黑树和set的结构串联

C++ map/set源码封装简单分析_第5张图片

可以看到红黑树结点中,实际存储的是第二个Key,只是被重命名成了value_type。为什么要这样呢?

我们接下来再看map


C++ map/set源码封装简单分析_第6张图片
map的模板参数有Key和Value,Key被重命名为key_typeT被重命名为data_type,但是还有一个pair被命名为value_type,并且传给红黑树的参数是key_type和value_type,也就是Key和pair

我们再将map和红黑树串联

C++ map/set源码封装简单分析_第7张图片
我们看到,map传给红黑树的是Key和pair,红黑树结点实际存储的是pair,也就是Key_Value,这样就实现了红黑树对map和set的套用了。

四. 分析

看到这,我们好像懂了些什么,但是又好像什么都没懂。
我们先提出一个疑问,红黑树对set和map的适配,好像都是依靠Value,也就是第二个参数,决定了红黑树内存储的是Key还是pair
那Key值的意义是什么呢?
首先,pair存储的是Key和Value。其次,map的个别接口,比如find,erase的参数是Key。同时红黑树要同时适配set和map,所以这些都要有。

五. KeyOfValue仿函数

红黑树的构建有一步非常关键的步骤,那就是结点的比较大小,因为较小的结点要放到左子树中,较大的结点要放到右子树中。红黑树存储的,实际都是map和set传过来的第二个参数,也就是Value。set传的是Key,而map传的pair。红黑树自己不知道上层传过来什么,所以无法直接用Value进行比较,这时就可以通过上层传的KeyOfValue仿函数,得到用来比较的Key了

set传的仿函数,直接返回Key即可
而map穿的仿函数,需要返回pair里的Key
大致实现如下:
C++ map/set源码封装简单分析_第8张图片

结束语

因为set和map的Key同样不能修改,所以迭代器其实都是const iterator
在这里插入图片描述

本篇文章,仅分析红黑树如何适配set和map,其实二者大部分都是对红黑树的一层封装,然后实现一些操作受限的功能接口。读者可以自行研究,有什么问题也欢迎评论区讨论

本篇内容到此就结束了,感谢你的阅读!

如果有补充或者纠正的地方,欢迎评论区补充,纠错。如果觉得本篇文章对你有所帮助的话,不妨点个赞支持一下博主,拜托啦,这对我真的很重要。
在这里插入图片描述

你可能感兴趣的:(C++学习笔记,数据结构与算法,c++,算法)