一、模拟实现map和set
1.1三个类模板的设计
template <class Key, class Value, class KeyOfValue, class Compare,
class Alloc = alloc>class rb_tree{};//红黑树类模板
template <class Key, class T, class Compare = less<Key>, class Alloc = alloc>
class map{};//map对红黑树进行了封装
template <class Key, class Compare = less<Key>, class Alloc = alloc>
class set{};//set对红黑树进行了封装
实际上红黑树类模板的第二个模板参数决定了红黑树的节点用来存放key还是pair;第一个模板参数是因为find之类的函数需要传递key,而第二个模板参数可能是pair无法实现实现直接使用key进行比较;第三个模板参数是为了解决insert是需要根据键值来进行搜索二叉树的建立,但是传递的参数是data,可能是键值,也可能是pair,所以需要使用仿函数,将key取出来,主要是为了map设计的;
为什么不使用仿函数直接比较而是返回key值,因为仿函数是最外层进行传入的,最外层传递比较方式,而内层的红黑树关心的是键值比较,所以红黑树使用KeyOfT;
1.2迭代器的设计
在rbtree中设计。
1.2.1begin/end
begin返回值是最左节点,end返回的是nullptr;
而库里面实现的是增加了一个哨兵位,使得哨兵位的左指向最小值,右指向最大值,end是哨兵位;好处是获取begin较快,但是删除和插入的成本增加了;
1.2.2++和- -的设计
++走中序遍历;
1.右不为空,访问右树的最左节点;
2.右为空,访问满足孩子是父亲的左孩子的最近祖先;
- - 反的走中序遍历
1.左不为空,访问左树的最右节点;
2.左为空,访问满足孩子是父亲的右孩子的最近祖先;
1.2.3const迭代器
RBTree通过模板参数实现const的迭代器类,set封装使用const迭代器来定义普通和const迭代器,即set使用的迭代器都是const迭代器;map使用pair<const K,V>来实现普通的迭代器不可以访问key;
1.2.4反向迭代器
1.3插入实现
注意返回值是pair,要注意对于set返回值要使用const迭代器的构造(普通迭代器对const迭代器的构造),因为普通迭代器和const迭代器会发生冲突;
对于tree迭代器类的设计其实是设计了一个迭代器的拷贝构造函数,set调用时变成普通迭代器对const迭代器的构造;然后tree迭代器内嵌了普通迭代器的类型。对于内嵌类型类外使用时不会给提示的,还必须typename修饰。
1.4operator[]
使用insert实现。
1.5map,tree,set的代码实现
namespace RbTree
{
enum Colour
{
RED,
BLACK,
};
template <class T>
struct RBTreeNode
{
RBTreeNode(const T &data) : data_(data), left_(nullptr), right_(nullptr), parent_(nullptr), col_(RED) {}
T data_;
RBTreeNode<T> *left_;
RBTreeNode<T> *right_;
RBTreeNode<T> *parent_;
Colour col_;
};
template <class T, class Ptr, class Ref>
struct __TreeIterator
{
typedef RBTreeNode<T> node;
typedef __TreeIterator<T, Ptr, Ref> Self;
typedef __TreeIterator<T, T *, T &> iterator;
__TreeIterator(node *node = nullptr) : node_(node) {}
__TreeIterator(const iterator &it) : node_(nullptr)
{
node_ = it.node_;
}
Ref operator*()
{
return node_->data_;
}
Ptr operator->()
{
return &(node_->data_);
}
Self &operator++()
{
if (node_->right_)
{
// 右不为空,访问右树的最左节点
node *subleft = node_->right_;
while (subleft->left_)
{