目录
RBTree改造
给红黑树增加迭代器
前置++
前置--
RBT细节改造
模拟set
模拟map
RBTree改造
给红黑树增加迭代器
前置++
前置++的作用是找下一个较大的节点。
假如我们it指向的是5,++it则是将it指向6。加入it指向的是7,则++it则是将it指向8。
也就是说如果右子树不为空,++it是指向的是右子树的最左节点(较大的)。
如果右子树为空(说明该子树已被访问完),++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 = cur->_parent;
parent = parent->_parent;
}
_node = parent;
}
return *this;
}
前置--
前置--的作用是找下一个较小的节点。
假如it指向的是8,--it则是将it指向7。假如it指向的是12,--it则就将it指向了11。
也就是说如果左子树不为空,--it是指向的是左子树的最右节点(较小的)。
如果左子树为空(说明该子树已被访问完),--it应该沿着根路径指向孩子是父亲右孩子的那个祖先。++it的顺序是左根右,--it的顺序是右根左。
//前置--
self& operator--() {
if (_node->_left) {
Node* max = _node->_left;
while (max->_right) {
max = max->_right;
}
_node = max;
}
else {
Node* cur = _node;
Node* parent = cur->_parent;
while (parent && cur == parent->_left) {
cur = parent;
parent = parent->_parent;
}
_node = parent;
}
return *this;
}
RBT细节改造
1、将节点存放数据的位置改为_data,也就是说无论是set还是map存放的数据都在这个_data里面。
template<class T>
struct rbtreeNode{
rbtreeNode<T>* _left;
rbtreeNode<T>* _right;
rbtreeNode<T>* _parent;
T _data;
Color _col;
rbtreeNode(const T& data)
:_left(nullptr)
,_right(nullptr)
,_parent(nullptr)
,_col(RED)
,_data(data)
{}
};
2、采用上边的方式的话,需要在RBTree中的函数模板中增加一个KeyOfT的仿函数,用于取set中的值,和map中的key进行比较。
3、迭代器的begin的位置应该找到最左节点(最小)
iterator begin() {
Node* min = _pHead;
while (min && min->_left) {
min = min->_left;
}
return iterator(min);
}
4、插入的返回值修改为pair<iterator,bool>类型,方便后边map的operator[]的实现
5、查找的返回值原本是Node*,而迭代器也相当于指针,所以也将放回置修改为迭代器
模拟set
set的底层就是红黑树,因此set的私有成员的类型就是红黑树。
RBTree<K, K, SetKeyOfT> _rt;
set里边需要写一个仿函数,让红黑树能拿到存储的数据。并将这个仿函数类型传给红黑树
struct SetKeyOfT {
const K& operator()(const K& k) {
return k;
}
};
其他的接口复用红黑树的就行了。完整的代码如下:
#pragma once
#include "RBTree1.h"
template<class K>
class mySet {
public:
struct SetKeyOfT {
const K& operator()(const K& k) {
return k;
}
};
typedef typename RBTree<K, K, SetKeyOfT>::iterator iterator;
iterator begin() {
return _rt.begin();
}
iterator end() {
return _rt.end();
}
pair<iterator,bool> insert(const K& key) {
return _rt.Insert(key);
}
iterator find(const K& key) {
return _rt.Find();
}
size_t size() {
return _rt.Size();
}
private:
RBTree<K, K, SetKeyOfT> _rt;
};
void test_MySet() {
mySet<int> ms;
int a[] = { 7,4,1,8,5,2,9,6,3 };
for (auto e : a) {
ms.insert(e);
}
mySet<int>::iterator it = ms.begin();
while (it != ms.end()) {
cout << *it << " ";
++it;
}
cout << endl;
cout << "size:" << ms.size() << endl;
}
模拟map
map的模拟和set类似,底层也是红黑树。我们这里说说map的operator[]的逻辑。insert的返回值是pair<iterator, bool>类型,insert插入原来没有的数据时,返回的是新插入节点的迭代器,并返回true。如果插入原本有的数据的时候,返回的是这个存在的key的迭代器,bool值为false。而operator[]就是依赖这个insert来实现的。operator[]的返回值是value的引用,也就是说我们可以通过operator[]对value进行查找、修改和插入等操作。