文章目录
- 一. 问题的抛出
- 二. 红黑树的实现
- 三. map/set实现
- 四. 分析
- 五. KeyOfValue仿函数
- 结束语
一. 问题的抛出
我们知道C++的STL中map和set的底层都是红黑树。
但是仔细思考一下,map是存储键值对,也就是Key_Value模型
而set是Key的模型
那么STL中的红黑树是如何实现适配这两种不同存储模型的。
我们从源码中,可以获取到我们想知道的答案
二. 红黑树的实现
我们首先来看一下红黑树结点的实现吧
可以看到STL中的红黑树结点的设计和我们学习的红黑树的结构大抵相同,只不过STL是使用bool值标记颜色
;
而且,红黑树的结点存储的只是Value
接下来,我们再看红黑树的类
我们先了解一下模板参数
Key:Key值
Value:Value值
KeyOfValue:从Value值中分离出Key
Compare:比较器
Alloc:内存池
比较器和内存池和本章内容关系不大,我们不考虑
我们主要要关注前三个参数
同时,我们看到,内部有node结点,但是传入的模板参数是Value,也是一个值。
看到这里,我们发现,STL的红黑树好像没什么特别的,也是存储单值的二叉搜索树,但是map存储的明明是Key_Value,一对键值对,map是如何使用这棵红黑树的呢?
那么接下来,我们就来看一下map和set的源码
三. map/set实现
我们首先查看set
的源码
set的模板参数只有Key
,但是我们看到Key被重命名成了两个属性,一个是key_type
,一个是value_type
,并且分别传入给了红黑树
红黑树的模板参数有一个Key,一个Value,但实际结点存储的只有Value。
接下来,我们将红黑树和set的结构串联
可以看到红黑树结点中,实际存储的是第二个Key,只是被重命名成了value_type。为什么要这样呢?
我们接下来再看map
map的模板参数有Key和Value,Key被重命名为key_type
,T被重命名为data_type
,但是还有一个pair<const Key,T>被命名为value_type
,并且传给红黑树的参数是key_type和value_type,也就是Key和pair
我们再将map和红黑树串联
我们看到,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<const K,V>。红黑树自己不知道上层传过来什么,所以无法直接用Value进行比较,这时就可以通过上层传的KeyOfValue仿函数,得到用来比较的Key了
set传的仿函数,直接返回Key即可
而map穿的仿函数,需要返回pair里的Key
大致实现如下:
结束语
因为set和map的Key同样不能修改,所以迭代器其实都是const iterator
本篇文章,仅分析红黑树如何适配set和map
,其实二者大部分都是对红黑树的一层封装,然后实现一些操作受限的功能接口。读者可以自行研究,有什么问题也欢迎评论区讨论
本篇内容到此就结束了,感谢你的阅读!
如果有补充或者纠正的地方,欢迎评论区补充,纠错。如果觉得本篇文章对你有所帮助的话,不妨点个赞支持一下博主,拜托啦,这对我真的很重要。