👀樊梓慕:个人主页
🎥个人专栏:《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》《C++》《Linux》《算法》
🌝每一个不曾起舞的日子,都是对生命的辜负
目录
前言
在之前的学习中,我们了解到set中存储的一般为键K即可,而map存储的一般都是键值对KV,也就是说他们结构是不同的,那么我们如何才能用一颗红黑树同时封装出set与map两种容器呢?
简单的说就是模板的使用,对于set存储的<K,K>,对于map存储的是<K,pair<K,V>>;
那么红黑树我们就可以使用模板,比如RBTree<K,T>,T就是这个模板类,当set使用时就是K,当map使用时就是pair。
那么接下来我们具体地来研究下STL库中是怎样实现的,并且进行模拟实现。
欢迎大家📂收藏📂以便未来做题时可以快速找到思路,巧妙的方法可以事半功倍。
=========================================================================
GITEE相关代码:🌟樊飞 (fanfei_c) - Gitee.com🌟
=========================================================================
1.红黑树模板参数的控制
template<class K, class T>
class RBTree
那么对于set:
template<class K>
class set
{
public:
//...
private:
RBTree<K, K> _t;
};
对于map:
template<class K, class V>
class map
{
public:
//...
private:
RBTree<K, pair<K, V>> _t;
};
即:
思考:既然对于map来说pair中有K,那么是不是可以将第一个模板参数省略呢?
- 对于set容器来说:可以,因为set传入红黑树的第二个参数与第一个参数是一样的;
- 对于map容器来说:不行,因为map容器所提供的接口当中有些是只要求给出键值Key的,比如find和erase。
2.红黑树节点的定义
//红黑树结点的定义
template<class T>
struct RBTreeNode
{
//三叉链
RBTreeNode<T>* _left;
RBTreeNode<T>* _right;
RBTreeNode<T>* _parent;
//存储的数据
T _data;
//结点的颜色
int _col;
//构造函数
RBTreeNode(const T& data)
: _left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _data(data)
, _col(RED)
{}
};
对于模板参数T来说,set使用就是K,map使用就是pair<K,V>,对应着set与map中节点存储的数据类型。
3.pair的比较规则引出红黑树仿函数设计
红黑树是一棵二叉搜索树,所以当我们寻找插入位置或者查找时一定会比较节点值之间的大小。
新插入节点值小于当前节点值,就往左走;
新插入节点值大于当前节点值,就往右走;
这是之前学习二叉搜索树最基本的特性,那么问题来了,对于map而言,节点值存储的是pair<K,V>,可是pair是依据什么来决定自身的大小呢?first?second?还是什么?
我们来看一下STL库中对pair比较大小的定义:
可我们期望的比较规则是这样么?
很明显不是,我们期望的是set与map都只依据Key来比较大小。
那么我们就需要想办法构造一个我们自己比较的方式出来。
首先比较的是Key,所以我们需要想办法取出Key,对于set而言那就是Key,对于map而言是pair的first,所以我们可以在红黑树中设计仿函数来统一设计,然后在set和map中具体实现即可。
set:
template<class K>
class set
{
//仿函数
struct SetKeyOfT
{
const K& operator()(const K& key) //返回键值Key
{
return key;
}
};
public:
//...
private:
RBTree<K, K, SetKeyOfT> _t;
};
map:
te