目录
1 红黑树
1.1 红黑树迭代器
难点是Increament和DeIncreament函数,用来实现迭代器的加加减减。下面讲解一下Increament的思路,DeIncreament思路与其大致思路相同,不过就是一个相反的关系。
红黑树按照中序遍历,当前节点加加就应该要到当前节点的右子树找最左节点,但是右节点有可能为null。因此就需要分右节点是否为空两种情况。
当右节点不为空,到右子树找最左节点。当右节点为空,说明以该节点为根的子树已经遍历完了,向上找父节点。如果父节点的左子树是当前节点,那么该父节点就是下一个节点。否则就是以父节点为根的子树也遍历完了,把父节点看作当前节点继续看其父节点,直到一个父节点的左子树是当前节点。
template<class T, class Ref, class Ptr>
class RBTreeIterator
{
typedef RBTreeNode<T> Node;
typedef Node* pNode;
typedef RBTreeIterator<T, Ref, Ptr> self;
public:
RBTreeIterator(const pNode& pnode) :_pNode(pnode) {}
Ref operator*()
{
return _pNode->val;
}
Ptr operator->()
{
return &_pNode->val;
}
self& operator++()
{
Increament();
return *this;
}
self operator++(int)
{
self temp = *this;
Increament();
return temp;
}
self& operator--()
{
DeIncreament();
return *this;
}
self operator--(int)
{
self temp = *this;
DeIncreament();
return temp;
}
bool operator==(const self& p)const
{
return _pNode == p._pNode;
}
bool operator!=(const self& p)const
{
return _pNode != p._pNode;
}
private:
void Increament()
{
if (_pNode->right)
{
Node* cur = _pNode->right;
while (cur->left)
{
cur = cur->left;
}
_pNode = cur;
}
else
{
Node* cur = _pNode;
Node* parent = _pNode->parent;
while (parent && parent->right == cur)
{
cur = parent;
parent = parent->parent;
}
_pNode = parent;
}
}
void DeIncreament()
{
if (_pNode->left)
{
Node* cur = _pNode->left;
while (cur->right)
{
cur = cur->right;
}
_pNode = cur;
}
else
{
Node* cur = _pNode;
Node* parent = _pNode->parent;
while (parent && parent->left == cur)
{
cur = parent;
parent = parent->parent;
}
_pNode = parent;
}
}
private:
pNode _pNode;
};
1.2 树
树的模板参数除了ValueType表示要存数据的类型,还有一个参数KeyOfValue表示传入一个仿函数。因为map的数据是一个pair键值对,数据比较时要比较的是第一个键的值,不能使用pair原生的比较方式,我们使用仿函数对其处理,由此可以做到map和set都可以使用这个树来实现。同时还把begin和end接口实现在树里,map和set的begin和end调用该接口就行了。
template<class T , class K>
class RBTree
{
public:
typedef RBTreeNode<T> Node;
typedef Node* pNode;
typedef RBTreeIterator<T, T&, T*> iterator;
public:
RBTree():_root(nullptr) {}
iterator begin()
{
pNode cur = _root;
while (cur->left)
{
cur = cur->left;
}
return iterator(cur);
}
iterator end()
{
return iterator(nullptr);
}
pair<iterator, bool> Insert(const T& data)
{
if (_root == nullptr)
{
_root = new Node(data);
_root->color = BLACK;
return std::make_pair(iterator(_root), true);
}
pNode cur = _root;
pNode parent = nullptr;
K k;
while (cur)
{
parent = cur;
if (k(cur->val) < k(data))
cur = cur->right;
else if (k(cur->val) > k(data))
cur = cur->left;
else
return std::make_pair(iterator(cur), false);
}
cur = new Node(data);
pNode newNode = cur;
if (k(parent->val) > k(data))
parent->left = cur;
else if (k(parent->val) < k(data))
parent->right = cur;
else
assert(false);
//控制平衡
。。。。。。
}
bool IsBalance();
private:
bool _isBanlance(pNode cur, int banchmark, int blacknum);
void RotateL(pNode parent);
void RotateR(pNode parent);
private:
pNode _root;
};
2 set
我们把树的接口做好,实现set类就很简单了。需要注意的就是SetKeyOfT中仿函数的实现了,set中只存储一个值,直接原样返回就行了。
#pragma once
#include "RBTree.h"
namespace lwh // 同上
{
template<class T>
class set
{
struct SetKeyOfT
{
const T& operator()(const T& data) { return data; }
};
public:
typename typedef RBTreeIterator<T, T&, T*> iterator;
set() :_t() {}
iterator begin()
{
return _t.begin();
}
iterator end()
{
return _t.end();
}
bool Insert(const T& data)
{
return _t.Insert(data).second;
}
private:
RBTree<T, SetKeyOfT> _t;
};
}
3 map
同样的map由于存储的键值对,就需要特别设置仿函数返回键值对中的键。还有就是[]符号重载,该符号先是在树中插入(以中括号中的内容为键),然后返回该键对应的内容。
#pragma once
#include <iostream>
namespace lwh
{
template<class K,class T>
class map
{
struct MapKeyOfT
{
const T& operator()(const std::pair<K, T>& data) { return data.first; }
};
public:
map() :_t() {}
typename typedef RBTree<std::pair<K, T>, MapKeyOfT>::iterator iterator;
iterator begin()
{
return _t.begin();
}
iterator end()
{
return _t.end();
}
pair<iterator, bool> Insert(const std::pair<K, T>& data)
{
return _t.Insert(data);
}
T& operator[](const K& key)
{
auto ret = _t.Insert(make_pair(key, T()));
return ret.first->second;
}
private:
RBTree<std::pair<K,T>, MapKeyOfT> _t;
};
}