一、红黑树结点设计
由于set是K模型的而map是KV模型的,并且他们两个都复用的是同一份红黑树代码,所以我们不能将红黑树的保存的数据类型定死,我们可以利用模版将data设置为T类型的,这样红黑树也不知道数据是什么类型的,只有set和map给他实例化的时候,传入什么类型数据就是什么类型
ps:红黑树实现博客
示意图:
二、红黑树插入设计
在插入的模块中,一定涉及到了结点数据大小的比较,由于红黑树本身并不知道数据data的类型是什么,可能是就是一个值,也可能是pair的结构体,所以不可以直接进行比较。例如set就是根据key值进行比较,而map虽然也是根据key值比较,但是key和value是封装正在pair中的,pair本身也是支持比较大小的,但是其比较逻辑不符合map,为了解决比较大小的问题,我们可以利用仿函数,返回需要比较的元素
ps:这里有一个问题,模版参数为什么要多一个K(key的类型)呢?set本身就是根据key进行比较的,写这个仿函数有什么意义呢?
【解释】:对于插入来说set和map都用不着这个K,但是对于Find来说map只需要根据key来查找,虽然pair中也存在key,但是用pair会很麻烦,为了让map使用key方便,所以多加了一个类型。而set不论是比较还是Find,set自己本身就不需要仿函数和多一个类型,但是由于set和map复用的是同一份红黑树的代码,为了兼容map,set也只能这样做了
三、迭代器
3.1 红黑树迭代器设计
template<class T, class Ref, class Ptr>
struct __RBTreeIterator
{
typedef RBTreeNode<T> Node;
typedef __RBTreeIterator<T, Ref, Ptr> Self;
Node* _node; //封装一个node
__RBTreeIterator(Node* node)
:_node(node)
{}
Ref operator*()
{
return _node->_data;
}
Ptr operator->()
{
return &_node->_data;
}
bool operator!=(const Self& s)
{
return _node != s._node;
}
}
3.2 迭代器++
红黑树的遍历是中序遍历,要满足左 根 右的遍历顺序,当迭代器++找下一个元素时,如果该节点存在右子树,下一个访问的节点一定是右子树的最左节点,如果该节点不存在右子树,就说明以该结点为根的子树已经全部访问过了,此时下一个访问的节点应该向上寻找,找节点是父亲结点左边的祖先(要注意下一个访问的节点不一定是父亲结点)
Self& operator++()
{
if (_node->_right)
{
Node *LeftMin = _node->_right;
while (LeftMin && LeftMin->_left)
{
LeftMin = LeftMin->_left;
}
_node = LeftMin;
}
else
{
// 找孩子为父亲左边的那个祖先
Node *cur = _node;
Node *parent = cur->_parent;
while (parent && parent->_right == cur)
{
cur = parent;
parent = parent->_parent;
}
_node = parent;
}
return *this;
}
3.3 迭代器Begin()与End()
Begin()返回的是树的最左节点,而End()一般返回的是最后一个节点的下一个节点,这里我们将它设置为空
Iterator Begin()
{
Node *LeftMin = _root;
while (LeftMin && LeftMin->_left)
{
LeftMin = LeftMin->_left;
}
return Iterator(LeftMin);
}
Iterator End()
{
return Iterator(nullptr);
}
四、map的[ ]实现
对于set和map来说,map还支持[ ],在方括号中传入key值,就会返回对应的value值,[ ]的实现其实是利用insert来实现的。插入函数的返回值其实是一个pair类型,第一个参数是结点的迭代器,第二个参数是bool类型,当插入对应的key时,若树中已存在,则设置该节点的迭代器并将bool置为false,如果是新插入的节点,也会返回这个节点的迭代器,并将bool置为true。所以我们需要将插入函数的返回值改变一下。
[ ]实现:
V& operator[](const K& key)
{
pair<iterator, bool> ret = _t.Insert(make_pair(key,V()));
return ret.first->second;
}
红黑树实现及set、map封装详细代码:begining: Record my growth - Gitee.com