一般来说封装需要实现map和set的迭代器,包括普通迭代器和const迭代器,其次是++和–操作,还有判断是否相等的重载
除此之外我们需要实现map和set的特性,例如set的值不允许修改,map的key不允许修改
set的构造参数只有一个,而map的构造参数有两个,我们怎么只用一个数据结构(红黑树)来封装两个容器呢
RBTree的模板参数前两个是K和T,K表示key关键字类型,T表示其中的数据类型
当用来构造map时刚刚好,一个用来存key,另一个用来存数据,这里我们考虑使用pair,分别存入const K和V,用来确保K不被修改
当用来构造set时,K和T是相同的,我们都传入K即可
RBTree的模板参数里面有一个KeyOfT,这是一个仿函数,因为map的结构特殊性,是一个pair,所以我们需要用仿函数来自动调用对应的取key中的T的操作,类似于C语言的回调函数,根据数据的类型调用不同的函数
在实现Insert函数时,返回值是一个pair,first是Node*,second是一个布尔值
这里的Node*一方面是需要返回给外部调用函数,另一方面是不能返回对应的迭代器和布尔类型,等下我们写到对应代码时再具体解释
template<class T>
struct __TreeIterator {
typedef RBTreeNode<T> Node;
typedef __TreeIterator<T> Self;
Node* _node;
__TreeIterator(Node* node)
:_node(node)
{
}
T& operator*() {
return _node->_data;
}
T* operator->() {
return &_node->_data;
}
bool operator!=(const Self& s) {
return _node != s._node;
}
bool operator==(const Self& s) {
return _node == s._node;
}
};
要实现++我们首先要明白++的本质是什么
一般来说迭代器的加减本身是用于寻找下一个(上一个)位置的迭代器,那对于红黑树这个数据结构来讲,他是中序有序的,因此我们要找的就是中序遍历的下一个节点
这里直接想其实是不容易的,我们通过例子来讲解
第一个例子是,1的下一个节点是6,8的下一个节点是11,17的下一个节点是22,那我们其实就发现,cur的右子树存在,直接走到他的右子树的最左节点即可,那么如果他的右节点不存在呢
第二个例子,6的下一个节点是8,11的下一个节点是13,15的下一个节点是17,22的下一个节点是25,规律不怎么明显,结论是如果右节点不存在则回溯,回溯到孩子是父亲左的第一个祖先节点
这个规律似乎很奇怪
但其实我们只需要想一下中序遍历的顺序:左子树、根、右子树
cur就是根,我们已经访问完了根,想要找他的下一个节点,那根的下一个就是右子树最左节点,如此往复,一直到没有右子树了,接下来寻找的孩子是父亲左的第一个节点,这句话实际上就保证了左子树全部被访问了,因此孩子是父亲左的第一个节点就是下一个cur,也就是根,接下来就需要继续访问右子树了
那类似的–的过程跟++的过程完全相反,找cur的左节点,如果左节点不存在则找孩子是父亲右的第一个节点
Self& operator++() {
if (_node->_right) {
Node* cur = _node->_right;
while (cur->_left) {
cur = cur->_left;
}
_node = cur;
}
else {
Node* cur = _node;
Node* parent = cur->_parent;
while (parent && cur == parent->_right) {
cur = parent;
parent = parent->_parent;
}
_node = parent;
}
return *this;
}
这里有个细节是parent为空时我们也认为他找到了,主要是需要包含根节点的情况
typedef __TreeIterator<T> iterator;
iterator begin() {
Node* cur = _root;
while (cur && cur->_left) {
cur = cur->_left;
}
return iterator(cur);
}
iterator end() {
return iterator(nullptr);
}
begin就是返回中序的第一个位置的迭代器,也就是最小的值,就是最左节点
end返回最后一个位置的下一个位置的迭代器,自然就是空指针
#pragma once
#include"RBTree.h"
namespace xu {
template<class K, class V>
class map {
public:
struct MapKeyOfT {
const K& operator() (const pair<K, V>& kv) {
return kv.first;
}
};
typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::iterator iterator;
typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::const_iterator const_iterator;
iterator begin() {
return _t.begin();
}
iterator end() {
return _t.end();
}
V& operator[](const K& key) {
pair<iterator, bool> ret = insert(make_pair(key, V()));
return ret.first->second;
}
pair<iterator, bool> insert(const pair<K, V>& kv) {
return _t.Insert(kv);
}
private:
RBTree<K, pair<const K, V