利用红黑树作为模板封装的思路
将红黑树作为一个基础的类模板,通过给这个类模板传递不同的参数,从而控制它所实现的容器。
最主要的点是用自己的map和set通过传递不同的模板参数控制红黑树第二个模板参数 T 来确定传入的到底是 Key 还是 pair<Key, Value> 类型的模板参数【泛型编程的思想】,如下图
红黑树的第二个参数T,通过传入参数的不同,控制红黑树中到底存储什么类型的变量。
给红黑树传的第三个模板参数 KeyOfT 是一个类,这个类中重载了 operator(),它实例化出的对象可以当做函数来使用,并且这个函数可以实现多种不同数据类型的大小比较,通过传进来类的不同,来使用不同的比较方式。
如图,KeyOfT示例化出的对象kot来进行树中的大小比较,当传 SetKeyOfT 时,就使用 key 作为比较依据;当传 MapKeyOfT 时,就使用 kv.first 作为大小比较依据。
迭代器的封装
首先,需要写一个迭代器的类模板,里面有迭代器变量主要需要使用的一些功能,如++,->,*,!=,==等等这些,通过传递不同的参数,来构造不同类型的迭代器。
迭代器的内部成员变量就是一个红黑树结点类型的指针,通过重载++,--,->等运算符作为成员函数。而模板参数传 Ref 和 Ptr 的原因是:当构造的是 const 类型或 非const 类型的迭代器时,编译器可以自己推导出返回值的类型。因为普通迭代器 iterator 和const类型的迭代器 const_iterator 不是同一个类型!
在红黑树中根据模板参数的不同重定义两个不同的迭代器:普通迭代器和 const 迭代器。当使用普通迭代器时,相当于给迭代器模板传<T, T&, T*>;当使用 const迭代器 时,相当于给迭代器模板传<T, const T&, const T*>
map 和 set 内部对于迭代器的处理
stl中 set 里的 key 不允许改变,因此无论是 iterator 还是 const_iterator,都需要使用红黑树中定义的 const_iterator 迭代器来初始化。
而map中,key不允许改变,T却可以改变,直接在模板参数中加 const 修饰K,普通迭代器用iterator,const 迭代器用 const_iterator修饰。
将insert 的返回值设置为 pair 类型,第一个 first 参数为 Node* 类型,因为无论是普通迭代器还是 const类型的迭代器,都是用 Node* 类型的变量来初始化的,只要是相近类型,pair的拷贝构造函数都能进行构造推导,推导为正确的类型!
代码实现
RBTree.h
#pragma once
#pragma once
#include<iostream>
#include<string>
#include<stdbool.h>
using namespace std;
typedef enum Color
{RED, // 红色BLACK // 黑色
}Color;
template<class T>
struct RBTreeNode
{RBTreeNode(const T& data):_right(nullptr), _left(nullptr), _parent(nullptr), _col(RED), _data(data){}RBTreeNode<T>* _right;RBTreeNode<T>* _left;RBTreeNode<T>* _parent;// 颜色:枚举类型Color _col;T _data;
};template<class T, class Ref, class Ptr>
struct __TreeIterator
{typedef RBTreeNode<T> Node;typedef __TreeIterator<T, Ref, Ptr> self;Node* _node;__TreeIterator(Node* node):_node(node){}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 && cur == parent->_left){cur = parent;parent = parent->_parent;}_node = parent;}return *this;}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 && cur == parent->_right){cur = parent;parent = parent->_parent;}_node = parent;}return *this;}bool operator==(const self& it){return _node == it._node;}bool operator!=(const self& it){return _node != it._node;}Ptr operator->(){return &_node->_data;}Ref operator*(){return _node->_data;}
};
template<class K, class T, class KeyOfT>
class RBTree
{typedef RBTreeNode<T> Node;
public:typedef __TreeIterator<T, T&, T*> iterator;typedef __TreeIterator<T, const T&, const T*> const_iterator;KeyOfT kot;iterator begin(){Node* cur = _root;while (cur->_left){cur = cur->_left; /*_t = cur; // 这个 _t 是根节点,不能随便变*/}return iterator(cur); //return *this;迭代器这里不能返回引用}iterator end(){return iterator(nullptr);}const_iterator begin() const{Node* cur = _root;while (cur->_left){cur = cur->_left;}return const_iterator(cur);}const_iterator end() const{return const_iterator(nullptr);}pair<Node*, bool> Insert(const T& data){if (_root == nullptr){_root = new Node(data);_root->_col = BLACK;return make_pair(_root, true);}//走到此处,说明根不为空Node* parent = nullptr;Node* cur = _root;while (cur){if (kot(cur->_data) < kot(data)){parent = cur;cur = cur->_right;}else if (kot(cur->_data)> kot(data)){parent = cur;cur = cur->_left;}else // 相等{return make_pair(cur, false);}}cur = new Node(data); // 初始化的时候就是红色结点cur->_parent = parent;// 调整父子之间的关系if (kot(parent->_data) < kot(data))parent->_right = cur;else if (kot(parent->_data) > kot(data))parent->_left = cur;Node* grandparent = parent->_parent;while (parent && parent->_col == RED){grandparent = parent->_parent;Node* uncle = nullptr;// 调整父亲和叔叔与爷爷的关系if (kot(parent->_data) > kot(grandparent->_data)){grandparent->_right = parent;uncle = grandparent->_left;}else if (kot(parent->_data) < kot(grandparent->_data)){grandparent->_left = parent;uncle = grandparent->_right;}// 新插入结点的父亲是红色结点,需要调整// 调整父亲和叔叔的左右if (uncle && uncle->_col == RED) // 叔叔存在并且为红色{grandparent->_col = RED;uncle->_col = parent->_col = BLACK;cur = grandparent;parent = cur->_parent;}else if (uncle == nullptr || uncle->_col == BLACK) // 叔叔不存在或者存在且为黑色,需要调整加变色{// 旋转都是将不均衡变为相对均衡,然后旋转后的父节点变为黑色,分到叔叔那边的结点变为红色// 因为这种情况,爷爷本来就是黑色if (parent == grandparent->_left){if (cur == parent->_left){RotateR(grandparent);parent->_col = BLACK;grandparent->_col = RED;}else if (cur == parent->_right){RotateL(parent);RotateR(grandparent);cur->_col = BLACK;grandparent->_col = RED;}}else{if (cur == parent->_left){RotateR(parent);RotateL(grandparent);grandparent->_col = RED;cur->_col = BLACK;}else if (cur == parent->_right){RotateL(grandparent);grandparent->_col = RED;parent->_col = BLACK;}}break;}}_root->_col = BLACK;return make_pair(cur, true);}bool IsValidRBTree(){Node* pRoot = _root;// 空树也是红黑树if (nullptr == pRoot)return true;// 检测根节点是否满足情况if (BLACK != pRoot->_col){cout << "违反红黑树性质二:根节点必须为黑色" << endl;return false;}// 获取任意一条路径中黑色节点的个数size_t blackCount = 0;Node* pCur = pRoot;while (pCur){if (BLACK == pCur->_col)blackCount++;pCur = pCur->_left;}// 检测是否满足红黑树的性质,k用来记录路径中黑色节点的个数size_t k = 0;return _IsValidRBTree(pRoot, k, blackCount);}bool _IsValidRBTree(Node* pRoot, size_t k, const size_t blackCount){//走到null之后,判断k和black是否相等if (nullptr == pRoot){if (k != blackCount){cout << "违反性质四:每条路径中黑色节点的个数必须相同" << endl;return false;}return true;}// 统计黑色节点的个数if (BLACK == pRoot->_col)k++;// 检测当前节点与其双亲是否都为红色Node* pParent = pRoot->_parent;if (pParent && RED == pParent->_colo && RED == pRoot->_col){cout << "违反性质三:没有连在一起的红色节点" << endl;return false;}return _IsValidRBTree(pRoot->_left, k, blackCount) &&_IsValidRBTree(pRoot->_right, k, blackCount);}void Order(){_Order(_root);cout << endl;}void _Order(Node* root){if (root == nullptr)return;_Order(root->_left);cout << root->_kv.first << " ";_Order(root->_right);}void RotateR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;Node* parentParent = parent->_parent;subL->_right = parent;parent->_parent = subL;parent->_left = subLR;if (subLR)subLR->_parent = parent;if (parent == _root){_root = subL;subL->_parent = nullptr;}else{if (parentParent->_left == parent){parentParent->_left = subL;}else if (parentParent->_right == parent){parentParent->_right = subL;}subL->_parent = parentParent;}}void RotateL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;Node* parentParent = parent->_parent;subR->_left = parent;parent->_parent = subR;if (subRL)subRL->_parent = parent;parent->_right = subRL;if (parent == _root){_root = subR;subR->_parent = nullptr;}else{// 先找到 parent 是父亲的左子树还是右子树if (parentParent->_left == parent) // 左子树{parentParent->_left = subR;}else if (parentParent->_right == parent) // 右子树{parentParent->_right = subR;}subR->_parent = parentParent;}}
private:Node* _root = nullptr;
};
MyMap.h
#pragma once
#include"RBTree.h"namespace zyb
{template<typename K, typename T>class map{public:struct MapKeyOfT{const K& operator()(const pair<const K, T>& kv){return kv.first;}};typedef typename RBTree<K, pair<const K, T>, MapKeyOfT>::iterator iterator;typedef typename RBTree<K, pair<const K, T>, MapKeyOfT>::const_iterator 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();}T& operator[](const K& key){pair<iterator, bool> ret = insert(make_pair(key, T()));return ret.first->second;}pair<iterator, bool> insert(const pair<const K, T>& kv){return _t.Insert(kv);}private:RBTree<K, pair<const K, T>, MapKeyOfT> _t;};
}
MySet.h
#pragma once
#include"RBTree.h"namespace zyb
{template<typename K>class set{public:struct SetKeyOfT{const K& operator()(const K& key){return key;}};typedef typename RBTree<K, K, SetKeyOfT>::const_iterator iterator;typedef typename RBTree<K, K, SetKeyOfT>::const_iterator const_iterator;pair<iterator, bool> insert(const K& key){return _t.Insert(key);}const_iterator begin() const{return _t.begin();}const_iterator end() const{return _t.end();}private:RBTree<K, K, SetKeyOfT> _t;};
}
可以使用以下用例对功能进行测试:
#include"RBTree.h"
#include"MyMap.h"
#include"MySet.h"
void test1(const zyb::set<int>& s1)
{zyb::set<int>::const_iterator it = s1.begin();while (it != s1.end()){cout << *it << " ";++it;}cout << endl;
}
void test2(const zyb::map<string, int>& m1)
{ zyb::map<string, int>::const_iterator it = m1.begin();while (it != m1.end()){cout << it->first << ":" << it->second << endl;++it;}cout << endl;
}
int main()
{zyb::set<int> s1;s1.insert(1);s1.insert(2);s1.insert(3);s1.insert(3);s1.insert(5);s1.insert(6);zyb::map<string, int> m1;m1.insert(make_pair("zyb", 1));m1.insert(make_pair("jn", 1));m1.insert(make_pair("yw", 1));test1(s1);test2(m1);return 0;
}