目录
STL中的set和map的底层都是用红黑树模拟实现的。但set每次只存储一个值,而map存储的是键值对,那是否要写两份红黑树的代码呢?
可写看下之前写的博客:可怕的红黑树_"派派"的博客-CSDN博客,实现是与map相似的。
我们可用模板对红黑树进行改造,让map和set同时适用。
在红黑树的代码中,我们可把存储每个节点的结构代码体更改为:
- enum Colour
- {
- RED,
- BLACK,
- };
-
- template<class T>
- struct RBTreeNode
- {
- RBTreeNode
* _left; - RBTreeNode
* _right; - RBTreeNode
* _parent; - T _data; // 存储数据
- Colour _col;
-
- RBTreeNode(const T& data)
- :_data(data)
- , _left(nullptr)
- , _right(nullptr)
- , _parent(nullptr)
- , _col(RED)
- {}
- };
其中根据T中的类型进行存储,例如:T可以是set传来的int类型等,map传来的键值对。
但在插入时需要比较数据的大小,T可能为int类型或则键值对。所以需要再增加一个仿函数,用来提取第一个参数(map和set都是用第一个参数比较大小的)。
set中:
- template<class K>
- class Set
- {
- struct SetKeyOfT
- {
- const K& operator()(const K& key)
- {
- return key;
- }
- };
- public:
- bool insert(const K& key)
- {
- return _t.Insert(key);
-
- }
-
- private:
- RBTree
_t; - };
map中:
- template<class K, class V>
- class Map
- {
- struct MapKeyOfT
- {
- const K& operator()(const pair
& kv) //提取第一个参数 - {
- return kv.first;
- }
- };
- public:
- bool insert(const pair
& kv) - {
- _t.Insert(kv);
-
- }
-
-
- private:
- RBTree
, MapKeyOfT> _t; - };
红黑树的代码部分:
- template<class K, class T, class KeyOfT>//keyOfT用来接收仿函数
- class RBTree
- {
- typedef RBTreeNode
Node; - public:
- bool Insert(const T& data)
- {
-
- if (_root == nullptr)
- {
- _root = new Node(data);
- _root->_col = BLACK;
-
- return true;
- }
-
- KeyOfT kot;
- 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 false;
- }
- }
- cur = new Node(data);
- Node* newnode = cur;
- cur->_col = RED;
- if (kot(parent->_data) < kot(data))
- {
- parent->_right = cur;
- }
- else
- {
- parent->_left = cur;
- }
- cur->_parent = parent;
- ..................
- ..................
- //旋转.....
- }
- }
画图理解下:

我们可验证下结果是否准确,可在红黑树中定义一个中序遍历代码,然后在set,map中调用。

- void test_set1()
- {
- Set<int> s;
- s.insert(8);
- s.insert(6);
- s.insert(5);
- s.insert(7);
- s.insert(2);
- s.insert(9);
- Map
int>m; - m.insert(make_pair("香蕉", 1));
- m.insert(make_pair("苹果", 1));
- m.insert(make_pair("西瓜", 1));
- m.insert(make_pair("草莓", 1));
- s.Inorder();
- cout << endl;
- m.Inorder();
- }
结果:
红黑树也是可以像string,vector一样,通过迭代器像指针一样去遍历节点,不过它更像list的迭代器,不是一个原生指针,而是通过封装了节点的指针,对指针进行操作。
在红黑树中增加下面的代码:
- typedef __RBTreeIterator
iterator; - typedef __RBTreeIterator
const T&, const T*> const_iterator; - iterator Begin()//找其最左节点
- {
- Node* subLeft = _root;
- while (subLeft && subLeft->_left)
- {
- subLeft = subLeft->_left;
- }
-
- return iterator(subLeft);
- }
-
- iterator End()
- {
- return iterator(nullptr);
- }
-
- const_iterator Begin() const
- {
- Node* subLeft = _root;
- while (subLeft && subLeft->_left)
- {
- subLeft = subLeft->_left;
- }
-
- return const_iterator(subLeft);
- }
-
- const_iterator End() const
- {
- return const_iterator(nullptr);
- }
-
- iterator Find(const K& key)//查找
- {
- Node* cur = _root;
- KeyOfT kot;
- while (cur)
- {
- if (kot(cur->_data) < key)
- {
- cur = cur->_right;
- }
- else if (kot(cur->_data) > key)
- {
- cur = cur->_left;
- }
- else
- {
- return iterator(cur);
- }
- }
-
- return End();
- }
迭代器的实现:
- template<class T, class Ref, class Ptr>
- struct __RBTreeIterator
- {
- typedef RBTreeNode
Node; - typedef __RBTreeIterator
Self; - Node* _node;
-
- __RBTreeIterator(Node* node)
- :_node(node)
- {}
-
- Ref operator*()
- {
- return _node->_data;
- }
-
- Ptr operator->()
- {
- return &_node->_data;
- }
-
- Self& operator++()
- {
- ............
- ............
- }
-
- Self operator++(int)
- {
- Self tmp(*this);
-
- ++(*this);
-
- return tmp;
- }
-
- Self& operator--()
- {
- ..........
- ..........
- }
-
- Self operator--(int)
- {
- Self tmp(*this);
-
- --(*this);
-
- return tmp;
- }
-
- 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 == nullptr)
- {
- // 找祖先里面,孩子是父亲左的那个
- Node* cur = _node;
- Node* parent = cur->_parent;
- while (parent && parent->_right == cur)
- {
- cur = cur->_parent;
- parent = parent->_parent;
- }
-
- _node = parent;
- }
- else
- {
- // 右子树的最左节点
- Node* subLeft = _node->_right;
- while (subLeft->_left)
- {
- subLeft = subLeft->_left;
- }
-
- _node = subLeft;
- }
- return *this;
- }
--的实现:
思路:当左子树不为空时,对其节点--,指向的是该左子树的最右节点。
当左子树为空时,对其节点--,之后指针是指向(在其祖先里,孩子是属于祖先右 孩子的)。
如图:

- Self& operator--()
- {
- if (_node->_left == nullptr)
- {
- Node* cur = _node;
- Node* parent = cur->_parent;
- while (parent && cur == parent->_left)
- {
- cur = cur->_parent;
- parent = parent->_parent;
- }
-
- _node = parent;
- }
- else
- {
- // 左子树的最右节点
- Node* subRight = _node->_left;
- while (subRight->_right)
- {
- subRight = subRight->_right;
- }
- _node = subRight;
- }
-
- return *this;
- }
当迭代器实现后,红黑树的插入代码要进行更改,insert函数返回值是pair,第一个参数是指向当前节点的迭代器,第二个参数是true/false;(插入成功返回true,否则返回false)。
set:
- template<class K>
- class Set
- {
- struct SetKeyOfT
- {
- const K& operator()(const K& key)
- {
- return key;
- }
- };
- public:
- typedef typename RBTree
::const_iterator iterator; - typedef typename RBTree
::const_iterator const_iterator; -
- iterator begin() const
- {
- return _t.Begin();
- }
-
- iterator end() const
- {
- return _t.End();
- }
-
- pair
bool > insert(const K& key) - {
- //pair
::iterator, bool> ret = - // _t.Insert(key);
- auto ret = _t.Insert(key);
- return pair
bool>(iterator(ret.first._node), ret.second); - }
-
- iterator find(const K& key)
- {
- return _t.Find(key);
- }
- private:
- RBTree
_t; - };
map代码:
- template<class K, class V>
- class Map
- {
- struct MapKeyOfT
- {
- const K& operator()(const pair
& kv) - {
- return kv.first;
- }
- };
- public:
- typedef typename RBTree
, MapKeyOfT>::iterator iterator; - typedef typename RBTree
, MapKeyOfT>::const_iterator const_iterator; -
- iterator begin()
- {
- return _t.Begin();
- }
-
- iterator end()
- {
- return _t.End();
- }
-
- pair
bool > insert(const pair& kv) - {
- return _t.Insert(kv);
- }
-
- iterator find(const K& key)
- {
- return _t.Find(key);
- }
-
- V& operator[](const K& key)
- {
- pair
bool> ret = insert(make_pair(key, V())); - return ret.first->second;
- }
-
- private:
- RBTree
, MapKeyOfT> _t; - };