利用红黑树封装实现map,set
目录
1.通用红黑树实现
1.1 初步结构实现
1.2 利用多模版改变传入参数
1.3 通用红黑树内部数据比较问题
1.4 map,set初步结构代码
2.通用红黑树迭代器实现
2.1 基本迭代器结构实现
2.2 operator++实现
2.2 operator--实现
3. map实现[ ]
4. 通用红黑树完整代码
5. 利用红黑树set,map代码
1.通用红黑树实现
1.1 初步结构实现
要利用红黑树封装map,set,发现map的参数是pair类型,而set只有key,正常的话可能会要实现两个红黑树分别对着两个结构进行封装,但是这两个红黑树的大部分接口都类似,此时就可以利用模版,根据传进去的参数,编译器进行实例化
// 枚举值表⽰颜⾊
enum Colour
{RED,BLACK
};
// 通用模版
template<class T>
struct RBTreeNode
{T _kv;RBTreeNode<T>* _left;RBTreeNode<T>* _right;RBTreeNode<T>* _parent;Colour _col;RBTreeNode(const T& kv):_kv(kv), _left(nullptr), _right(nullptr), _parent(nullptr){}
};
template<class T>
class RBTree
{typedef RBTreeNode<T> Node;
public://接口实现
private:Node* _root = nullptr;
};
1.2 利用多模版改变传入参数
对于set,find/erase/insert时的函数参数都是Key,因此一个模版就可以,但是对于map,虽然find/erase/时的函数参数也是一样的,但是insert函数时插入的数据时pair类型,因此只有一个模版参数是无法使用的,此时就可以多使用一个模版参数就可以区分,对于set来说K,T两个模版参数都是一样的,对于map,K存储pair类型的first数据,T存储pair类型
//set,一个模版参数就可以
Node* Find(const K& key)
bool Insert(const K& key)
Node* erase(const K& key)
//map,需要两个模版参数,K存储pair类型的first数据,T存储pair类型
Node* Find(const K& key)
bool Insert(const T& kv)
Node* erase(const K& key)
template<class K,class T>
class RBTree
{typedef RBTreeNode<T> Node;
public:
//利用不同模版参数,控制不同形参传入bool Insert(const T& kv)Node* Find(const K& key)private:Node* _root = nullptr;
};
1.3 通用红黑树内部数据比较问题
在上文,对于不同参数的传入,利用了模版解决,这时又有新的问题,来看看下面关于find的代码
Node* Find(const K& key)
{Node* cur = _root;while (cur){if (cur->_kv.first < key){cur = cur->_right;}else if (cur->_kv.first > key){cur = cur->_left;}else{return cur;}}return nullptr;
}
发现这里cur内的参数是pair,利用pair的first数据比较,这里对于map来说没有问题,但是对于set就有问题,因为set没有first,这是就可以利用仿函数解决,对红黑树加入一个仿函数模版比较
通用find代码实现
template<class K,class T, class KeyOfT>//KeyOfT仿函数模版
class RBTree
{typedef RBTreeNode<T> Node;
public:bool Insert(const T& kv)Node* Find(const K& key)
{Node* cur = _root;KeyOfT kot;while (cur){if (kot(cur->_kv) < kot(kv)){cur = cur->_right;}else if (kot(cur->_kv) > kot(kv)){cur = cur->_left;}else{return cur;}}return nullptr;
}
private:Node* _root = nullptr;
};
1.4 map,set初步结构代码
map.h
namespace chuxin
{template<class K, class V>class map{struct MapKeyOfT{//利用仿函数const K& operator()(const pair<K, V>& kv){return kv.first;}};public:private:RBTree<K, pair< K, V>, MapKeyOfT> _t;};
}
set.h
namespace chuxin
{template<class K>class set{struct SetKeyOfT{const K& operator()(const K& key){return key;}};public:private:RBTree<K, K, SetKeyOfT> _t;};
}
2.通用红黑树迭代器实现
2.1 基本迭代器结构实现
这里的迭代器基本结构和list迭代器类似,都是用指针封装迭代器,如果不清楚list迭代器失现,请移步list类的常用接口实现及迭代器,这里就不在叙述,同样由于红黑树的迭代器支持 ->,因此也需要多个参数模版实现
template<class T>
struct RBTreeNode
{T _kv;RBTreeNode<T>* _left;RBTreeNode<T>* _right;RBTreeNode<T>* _parent;Colour _col;RBTreeNode(const T& kv):_kv(kv), _left(nullptr), _right(nullptr), _parent(nullptr){}
};
template<class T, class Ref, class Ptr>//利用指针封装迭代器
struct RBTreeIterator
{typedef RBTreeNode<T> Node;typedef RBTreeIterator<T, Ref, Ptr> Self;Node* _node;RBTreeIterator(Node* node):_node(node){}Ref operator*(){return _node->_kv;}Ptr operator->(){return &_node->_kv;}bool operator!= (const Self& s) const{return _node != s._node;}bool operator== (const Self& s) const{return _node == s._node;}
};
set的iterator也不⽀持修改,我们把set的第⼆个模板参数改成const K即可,
RBTree<K,const K, SetKeyOfT> _t
map的iterator不⽀持修改key但是可以修改value,我们把map的第⼆个模板参数pair的第⼀个参
数改成const K即可
RBTree<K, pair<const K, V>, MapKeyOfT> _t
2.2 operator++实现
map和set的迭代器⾛的是中序遍历,左⼦树->根结点->右⼦树,那么begin()会返回中序第⼀个结点(左子树的最左节点)的iterator也就是10所在结点的迭代器。

对于++有以下两个场景
迭代器++时,如果it指向的结点的右⼦树不为空,代表当前结点已经访问完了,要访问下⼀个结点是右⼦树的中序第⼀个,⼀棵树中序第⼀个是最左结点,所以直接找右⼦树的最左结点即可。
Self operator++()
{// 右不为空,中序下一个访问的节点是右子树的最左(最小)节点if (_node->_right){Node* min = _node->_right;while (min->_left){min = min->_left;}_node = min;}// 右为空else{}
}
迭代器++时,如果it指向的结点的右⼦树空,代表当前结点已经访问完了且当前结点所在的⼦树也访问完了,要访问的下⼀个结点在当前结点的祖先⾥⾯,所以要沿着当前结点到根的祖先路径向上找。

Self operator++(){// 右不为空,中序下一个访问的节点是右子树的最左(最小)节点if (_node->_right){Node* min = _node->_right;while (min->_left){min = min->_left;}_node = min;}// 右为空else{Node* cur = _node;Node* parent = cur->_parent;while (parent && cur == parent->_right){cur = parent;parent = cur->_parent;}_node = parent;}}
2.2 operator--实现
迭代器--的实现跟++的思路完全类似,逻辑正好反过来即可,因为他访问顺序是右⼦树->根结点->
左⼦树。
end()如何表⽰呢?如下图:当it指向50时,++it时,50是40的右,40是30的右,30是18的右,18
到根没有⽗亲,没有找到孩⼦是⽗亲左的那个祖先,这是⽗亲为空了,那我们就把it中的结点指针
置为nullptr,我们⽤nullptr去充当end。

对于--end(),特殊处理,走到中序最后一个结点,整棵树的最右结点,因此需要_root节点
template<class T, class Ref, class Ptr>//利用指针封装迭代器
struct RBTreeIterator
{typedef RBTreeNode<T> Node;typedef RBTreeIterator<T, Ref, Ptr> Self;Node* _node;Node* _root;RBTreeIterator(Node* node,Node* root):_node(node),_root(root){}
Self operator--()
{if (_node == nullptr) // --end(){// --end(),特殊处理,走到中序最后一个结点,整棵树的最右结点Node* rightMost = _root;while (rightMost && rightMost->_right){rightMost = rightMost->_right;}_node = rightMost;}else if (_node->_left){// 左子树不为空,中序左子树最后一个Node* rightMost = _node->_left;while (rightMost->_right){rightMost = rightMost->_right;}_node = rightMost;}else{// 孩子是父亲右的那个祖先Node* cur = _node;Node* parent = cur->_parent;while (parent && cur == parent->_left){cur = parent;parent = cur->_parent;}_node = parent;}return *this;
}
3. map实现[ ]
map要⽀持[ ]主要需要修改insert返回值⽀持,修改RBtree中的insert返回值为
pair<Iterator, bool> Insert(const T& data)
V& operator[](const K& key){pair<iterator, bool> ret = insert({ key, V() });return ret.first->second;}
4. 通用红黑树完整代码
#include<iostream>
#include<assert.h>
using namespace std;
// 枚举值表⽰颜⾊
enum Colour
{RED,BLACK
};
// 通用模版
template<class T>
struct RBTreeNode
{T _kv;RBTreeNode<T>* _left;RBTreeNode<T>* _right;RBTreeNode<T>* _parent;Colour _col;RBTreeNode(const T& kv):_kv(kv), _left(nullptr), _right(nullptr), _parent(nullptr){}
};
template<class T, class Ref, class Ptr>//利用指针封装迭代器
struct RBTreeIterator
{typedef RBTreeNode<T> Node;typedef RBTreeIterator<T, Ref, Ptr> Self;Node* _node;Node* _root;RBTreeIterator(Node* node,Node* root):_node(node),_root(root){}Ref operator*(){return _node->_kv;}Ptr operator->(){return &_node->_kv;}bool operator!= (const Self& s) const{return _node != s._node;}bool operator== (const Self& s) const{return _node == s._node;}Self operator++(){// 右不为空,中序下一个访问的节点是右子树的最左(最小)节点if (_node->_right){Node* min = _node->_right;while (min->_left){min = min->_left;}_node = min;}// 右为空else{Node* cur = _node;Node* parent = cur->_parent;while (parent && cur == parent->_right){cur = parent;parent = cur->_parent;}_node = parent;}return *this;}Self operator--(){if (_node == nullptr) // --end(){// --end(),特殊处理,走到中序最后一个结点,整棵树的最右结点Node* rightMost = _root;while (rightMost && rightMost->_right){rightMost = rightMost->_right;}_node = rightMost;}else if (_node->_left){// 左子树不为空,中序左子树最后一个Node* rightMost = _node->_left;while (rightMost->_right){rightMost = rightMost->_right;}_node = rightMost;}else{// 孩子是父亲右的那个祖先Node* cur = _node;Node* parent = cur->_parent;while (parent && cur == parent->_left){cur = parent;parent = cur->_parent;}_node = parent;}return *this;}
};
template<class K,class T, class KeyOfT>
class RBTree
{typedef RBTreeNode<T> Node;
public:// 旋转代码的实现跟AVL树是⼀样的,只是不需要更新平衡因⼦typedef RBTreeIterator<T, T&, T*> Iterator;typedef RBTreeIterator<T, const T&, const T*> ConstIterator;Iterator Begin(){Node* cur = _root;while (cur && cur->_left){cur = cur->_left;}return Iterator(cur, _root);}Iterator End(){return Iterator(nullptr, _root);}ConstIterator Begin() const{Node* cur = _root;while (cur && cur->_left){cur = cur->_left;}return ConstIterator(cur, _root);}ConstIterator End() const{return ConstIterator(nullptr, _root);}pair<Iterator, bool> Insert(const T& kv){if (_root == nullptr){_root = new Node(kv);_root->_col = BLACK;return {Iterator(_root,_root),true};}Node* parent = nullptr;Node* cur = _root;KeyOfT kot;while (cur){if (kot(cur->_kv) < kot(kv)){parent = cur;cur = cur->_right;}else if (kot(cur->_kv) > kot(kv)){parent = cur;cur = cur->_left;}else{return { Iterator(cur,_root),false };}}cur = new Node(kv);// 新增结点。颜⾊红⾊给红⾊Node* newnode = cur;cur->_col = RED;if (kot(parent->_kv) < kot(kv)){parent->_right = cur;}else{parent->_left = cur;}cur->_parent = parent;//变色while (parent && parent->_col == RED){Node* grandfather = parent->_parent;if (parent == grandfather->_left){Node* uncle = grandfather->_right;// u存在且为红 -》变⾊再继续往上处理if (uncle && uncle->_col == RED){parent->_col = uncle->_col = BLACK;grandfather->_col = RED;cur = grandfather;parent = cur->_parent;}else{//u不存在或存在且为⿊if (cur == parent->_left){//右单旋RotateR(grandfather);parent->_col = BLACK;grandfather->_col = RED;}else{//左右双旋RotateL(parent);RotateR(grandfather);cur->_col = BLACK;grandfather->_col = RED;}break;}}else{Node* uncle = grandfather->_left;// 叔叔存在且为红,-》变⾊即可if (uncle && uncle->_col == RED){parent->_col = uncle->_col = BLACK;grandfather->_col = RED;// 继续往上处理cur = grandfather;parent = cur->_parent;}else{//u不存在或存在且为⿊if (cur == parent->_right){//左单旋RotateL(grandfather);parent->_col = BLACK;grandfather->_col = RED;}else{//右左双旋RotateR(parent);RotateL(grandfather);cur->_col = BLACK;grandfather->_col = RED;}break;}}}_root->_col = BLACK;return { Iterator(newnode,_root),true };}void RotateR(Node* parent)//右单旋{Node* subL = parent->_left;Node* subLR = subL->_right;subL->_right = parent;parent->_left = subLR;Node* parendP = parent->_parent;if (subLR)subLR->_parent = parent;parent->_parent = subL;if (parendP == nullptr){_root = subL;subL->_parent = nullptr;}else//当旋转的是某一颗树的子树{if (parent == parendP->_left){parendP->_left = subL;}else{parendP->_right = subL;}subL->_parent = parendP;}}void RotateL(Node* parent)//左单旋{Node* subR = parent->_right;Node* subRL = subR->_left;parent->_right = subRL;if (subRL)subRL->_parent = parent;Node* parentParent = parent->_parent;subR->_left = parent;parent->_parent = subR;if (parentParent == nullptr){_root = subR;subR->_parent = nullptr;}else{if (parent == parentParent->_left){parentParent->_left = subR;}else{parentParent->_right = subR;}subR->_parent = parentParent;}}Node* Find(const K& key){Node* cur = _root;KeyOfT kot;while (cur){if (kot(cur->_kv) < kot(key)){cur = cur->_right;}else if (kot(cur->_kv) > kot(key)){cur = cur->_left;}else{return cur;}}return nullptr;}void InOrder(){_InOrder(_root);cout << endl;}int Size(){return _Size(_root);}
private:int _Size(Node* root){if (root == nullptr)return 0;return _Size(root->_left) + _Size(root->_right) + 1;}void _InOrder(Node* root){if (root == nullptr){return;}_InOrder(root->_left);cout << root->_kv.first << ":" << root->_kv.second << endl;_InOrder(root->_right);}private:Node* _root = nullptr;
};
5. 利用红黑树set,map代码
map
namespace chuxin
{template<class K, class V>class map{struct MapKeyOfT{//利用仿函数const K& operator()(const pair<K, V>& kv){return kv.first;}};public:typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::Iterator iterator;typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::ConstIterator const_iterator;iterator begin(){return _t.Begin();}iterator end(){return _t.End();}const_iterator begin() const{return _t.Begin();}const_iterator end() const{return _t.End();}pair<iterator, bool> insert(const pair<K, V>& kv){return _t.Insert(kv);}V& operator[](const K& key){pair<iterator, bool> ret = insert({ key, V() });return ret.first->second;}private:RBTree<K, pair<const K, V>, MapKeyOfT> _t;};
}
set
#include"RBtree.h"
namespace chuxin
{template<class K>class set{struct SetKeyOfT{const K& operator()(const K& key){return key;}};public:typedef typename RBTree<K, const K, SetKeyOfT>::Iterator iterator;typedef typename RBTree<K, const K, SetKeyOfT>::ConstIterator const_iterator;iterator begin(){return _t.Begin();}iterator end(){return _t.End();}const_iterator begin() const{return _t.Begin();}const_iterator end() const{return _t.End();}pair<iterator, bool> insert(const K& key){return _t.Insert(key);}private:RBTree<K, const K, SetKeyOfT> _t;};
}