持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第8天,点击查看活动详情
STL明确规定,begin()与end()代表的是一段前闭后开的区间
对红黑树进行中序遍历后,可以得到一个有序的序列,因此begin()可以放在红黑树中最小节点(即最左侧节点)的位置,end()放在最大节点(最右侧节点)的下一个位置即nullptr
2.operator++()与operator--()
Self& operator++()
{
if (_node->_right)//右子节点存在
{
//找到右子树中最左节点
Node* cur = _node->_right;
while (cur->_left)
{
cur = cur->_left;
}
_node = cur;
}
else//右子节点不存在,向上找
{
Node* cur = _node;//记录走过的节点
Node* parent = _node->_parent;
while (parent && parent->_right == cur)
{
cur = parent;
parent = parent->_parent;
}
_node = parent;
}
return *this;
}
Self& operator--()
{
if (_node->_left)//左子节点存在
{
//找左子树中的最右节点
Node* cur = _node->_left;
while (cur->_right)
{
cur = cur->_right;
}
_node = cur;
}
else//左子节点不存在
{
Node* cur = _node;
Node* parent = _node->_parent;
while (parent && parent->_left == cur)
{
cur = parent;
parent = parent->_parent;
}
_node = parent;
}
return *this;
}
因为反向迭代器与正向迭代器在原理实现中是相同的,只是方向反了而已 所以我们可以用正向迭代器来封装出反向迭代器,在正向迭代器的基础上,对其接口进行封装达到反向迭代器的效果
template<class T, class Ref, class Ptr>
struct _TreeIterator
{
//声明类型,便于反向迭代器对类型的提取
typedef Ref reference;
typedef Ptr pointer;
typedef RBTreeNode<T> Node;
typedef _TreeIterator<T, Ref, Ptr> Self;
Node* _node;
_TreeIterator(Node* node)
:_node(node)
{}
Ref operator*()
{
return _node->_data;
}
Ptr operator->()
{
return &_node->_data;
}
bool operator==(const Self& it)const
{
return _node == it._node;
}
bool operator!= (const Self& it)const
{
return _node != it._node;
}
Self& operator++()
{
if (_node->_right)
{
Node* cur = _node->_right;
while (cur->_left)
{
cur = cur->_left;
}
_node = cur;
}
else
{
Node* cur = _node;
Node* parent = _node->_parent;
while (parent && parent->_right == cur)
{
cur = parent;
parent = parent->_parent;
}
_node = parent;
}
return *this;
}
Self& operator--()
{
if (_node->_left)
{
Node* cur = _node->_left;
while (cur->_right)
{
cur = cur->_right;
}
_node = cur;
}
else
{
Node* cur = _node;
Node* parent = _node->_parent;
while (parent && parent->_left == cur)
{
cur = parent;
parent = parent->_parent;
}
_node = parent;
}
return *this;
}
};
//适配器构造反向迭代器
template<class Iterator>
struct ReverseIterator
{
//类型未实例化,无法取出里面的类型,此时需要使用typename:告诉编译器等实例化后再到类里面找对应的类型
typedef typename Iterator::reference Ref;
typedef typename Iterator::pointer Ptr;
typedef ReverseIterator<Iterator> Self;
Iterator _it;
ReverseIterator(Iterator it)
:_it(it)
{}
//在正向迭代器接口上进行封装复用
Ref operator*()
{
return *_it;
}
Ptr operator->()
{
return _it.operator->();
}
bool operator==(const Self& it)const
{
return it._it==_it;
}
bool operator!= (const Self& it)const//两个const
{
return _it != it._it;
}
Self& operator++()
{
--_it;
return *this;
}
Self& operator--()
{
++_it;
return *this;
}
};
因为set是K模型的容器,而map是KV模型的容器.所以要用红黑树来模拟实现这两个容器,需要添加一些东西使得其能适配两者,添加和改变的东西如下:
对于红黑树的节点我们需要节点对于set来说储存key,对于map来说储存key-value键值对,所以这里我们就直接让节点类型的阈值类型为T,用来控制储存类型
template<class T>
struct RBTreeNode
{
RBTreeNode<T>* _left;
RBTreeNode<T>* _right;
RBTreeNode<T>* _parent;
T _data;//T可以是key也可以是pair<K,V>
Colour _col;
RBTreeNode(const T& data)
:_left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _data(data)
, _col(RED)
{}
};
template<class K, class T>
class RBTree
{
typedef RBTreeNode<T> Node;
public:
//.......
private:
Node* _root;
};
K是用来比较的类型,T是用来存储的类型
在删除添加时,我们要进行节点中数据的比较, 当为map时,pirpair<key,value>与Kl类型无法比较时,这里就需要仿函数来帮助我们适配
仿函数的本质是创造一个类,通过operator()的重载来实现的,与函数重载类似,但在模板内,就只能使用仿函数来实现了。
template<class K, class T, class KeyOfT>
class RBTree
{
typedef RBTreeNode<T> Node;
public:
//...
private:
Node* _root;
};
namespace cole
{
template<class K, class V>
class map
{
struct MapOfKey
{
const K& operator()(const pair<K, V>& kv)
{
return kv.first;
}
};
public:
//...
private:
RBTree<K, pair<const K, V>, MapOfKey> _t;
};
}
namespace cole
{
template<class K>
class set
{
struct SetOfKey
{
const K& operator()(const K& key)
{
return key;
}
};
public:
//...
private:
RBTree<K, K, SetOfKey> _t;
};
}