目录
1、红黑树
红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出俩倍,因而是接近平衡的。
红黑树的性质
1. 每个结点不是红色就是黑色
2. 根节点是黑色的
3. 如果一个节点是红色的,则它的两个孩子结点是黑色的
4. 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均 包含相同数目的黑色结点
5. 每个叶子结点都是黑色的(此处的叶子结点指的是空结点)
2、红黑树的定义:
enum color {
RED,
BLACK
};
// 为了后序封装map和set,在实现时给红黑树多增加了一个头结点
template<class K, class T, class KeyOfT>
class RBTree
{
typedef RBTreeNode<T> Node;
typedef __RBTreeIterator<T, T&, T*> iterator;
KeyOfT keyoft;
public:
RBTree()
{
_pHead = new Node;
_pHead->_pLeft = _pHead;
_pHead->_pRight = _pHead;
}
iterator begin() { return LeftMost(); }
iterator end() { return RightMost(); }
// 在红黑树中插入值为data的节点,
// 注意:为了简单起见,本次实现红黑树不存储重复性元素
pair<iterator, bool> Insert(const T& data);
// 检测红黑树中是否存在值为data的节点,存在返回该节点的地址,否则返回nullptr
Node* Find(const T& data) {
Node* cur = GetRoot();
while (cur) {
if (keyoft(data) == keyoft(cur->_data)) {
return cur;
}
else if (keyoft(data) < keyoft(cur->_data)) {
cur = cur->_pLeft;
}
else if (keyoft(data) > keyoft(cur->_data)) {
cur = cur->_pRight;
}
}
return cur;
}
// 获取红黑树最左侧节点
Node* LeftMost() {
Node* cur = _pHead->_pParent;
while (cur) {
if (!cur->_pLeft) {
return cur;
}
cur = cur->_pLeft;
}
return cur;
}
// 获取红黑树最右侧节点
Node* RightMost() {
Node* cur = _pHead->_pParent;
while (cur) {
if (!cur->_pRight) {
return cur;
}
cur = cur->_pRight;
}
return cur;
}
//中序遍历
void Inorder() {
_inorder(GetRoot());
cout << endl;
}
// 检测红黑树是否为有效的红黑树,注意:其内部主要依靠_IsValidRBTRee函数检测
bool IsValidRBTRee() {
size_t black = 0;
return _IsValidRBTree(GetRoot()->_pLeft, 1, black) && _IsValidRBTree(GetRoot()->_pRight, (size_t)1, black);;
}
private:
void _inorder(Node* root) {
if (!root) {
return;
}
_inorder(root->_pLeft);
cout << keyoft(root->_data) << " ";
_inorder(root->_pRight);
}
bool _IsValidRBTree(Node* root, size_t blackCount, size_t& pathBlack) {
if (!root) {
if (pathBlack == 0) {
pathBlack = blackCount;
return true;
}
if (blackCount != pathBlack) {
return false;
}
}
if (root->_col == RED && root->_pParent->_col == RED) {
return false;
}
if (root->_col == BLACK)
++blackCount;
return _IsValidRBTree(root->_pLeft, blackCount, pathBlack) && _IsValidRBTree(root->_pRight, blackCount, pathBlack);
}
// 左单旋
void RotateL(Node* cur);
// 右单旋
void RotateR(Node* cur);
// 为了操作树简单起见:获取根节点
Node*& GetRoot() {
return _pHead->_pParent;
}
private:
Node* _pHead;
};
3、红黑树插入的平衡过程
红黑树在插入的时候,也是根据二叉搜索树的插入规则去插入,插入的新节点的颜色,我们选择将他定义成红色,这样可以省去很多麻烦。
插入节点之后,红黑树的结构可能会被破坏,违背性质中的某几条,
因此我们需要对其进行调整:
插入以及调整思路
pair<iterator, bool> Insert(const T& data) {
Node* node = new Node(data,RED);
//红黑树为空
if (!GetRoot()) {
GetRoot() = node;
node->_pParent = _pHead;
node->_col = BLACK;
_pHead->_pLeft = LeftMost();
_pHead->_pRight = RightMost();
return make_pair(iterator(node), true);
}
//插入非根节点
Node* cur = GetRoot();
while (cur) {
if (keyoft(node->_data) < keyoft(cur->_data)) {
if (!cur->_pLeft) {
cur->_pLeft = node;
node->_pParent = cur;
break;
}
cur = cur->_pLeft;
}
else if (keyoft(node->_data) > keyoft(cur->_data)) {
if (!cur->_pRight) {
cur->_pRight = node;
node->_pParent = cur;
break;
}
cur = cur->_pRight;
}
else {
delete node;
return make_pair(iterator(cur), false) ;
}
}
//插入完成后需要更新头结点的左右节点
_pHead->_pLeft = LeftMost();
_pHead->_pRight = RightMost();
//检查当前是否符合红黑树的性质
cur = node;
Node* parent = cur->_pParent;
Node* grendpa = nullptr;
Node* uncle = nullptr;
while (parent != _pHead) {
//更新爷爷节点和叔叔节点
grendpa = parent->_pParent;
uncle = nullptr;
if (parent == grendpa->_pLeft)
uncle = grendpa->_pRight;
else
uncle = grendpa->_pLeft;
//判断
if (parent->_col == BLACK)
//如果父亲结点为黑色,符合红黑树性质,直接跳出
break;
else if (parent->_col == RED && uncle && uncle->_col == RED) {
//如果父亲节点为红色,且叔叔节点也为红色
//那就将父亲和叔叔节点的颜色改为黑色,将爷爷结点改为红色,继续网上更新
parent->_col = BLACK;
uncle->_col = BLACK;
grendpa->_col = RED;
//更新cur和parent结点
cur = grendpa;
parent = cur->_pParent;
}
else if (parent->_col == RED && (uncle == nullptr || uncle->_col == BLACK)) {
//如果父亲的节点为红色,且叔叔节点的颜色为黑色,此时需要进行旋转
//这里分为四种情况:
// 1、cur结点为parent的左节点,同时parent也是grendpa的左节点
// 2、cur结点为parent的右节点,同时parent也是grendpa的右节点
// 以上两种情况只需要进行右单旋或者左单旋就可以解决
// 3、cur结点为parent的左节点,同时parent是grendpa的右节点
// 4、cur结点为parent的右节点,同时parent是grendpa的左节点
// 以上两种情况需要进行双旋解决
if (cur == parent->_pLeft && parent == grendpa->_pLeft) {
//进行右单旋
RotateR(cur);
parent->_col = BLACK;
grendpa->_col = RED;
}
else if (cur == parent->_pRight && parent == grendpa->_pRight) {
//左单旋
RotateL(cur);
parent->_col = BLACK;
grendpa->_col = RED;
}
else if (cur == parent->_pLeft && parent == grendpa->_pRight){
//先右单旋,在左单旋
RotateR(cur);
RotateL(cur);
cur->_col = BLACK;
grendpa->_col = RED;
}
else if (cur == parent->_pRight && parent == grendpa->_pLeft) {
//先左单旋,在右单旋
RotateL(cur);
RotateR(cur);
cur->_col = BLACK;
grendpa->_col = RED;
}
break;
}
}
//更新根节点为黑色
GetRoot()->_col = BLACK;
return make_pair(iterator(node), true);
}
红黑树的左旋和右旋实现
// 左单旋
void RotateL(Node* cur) {
Node* left = cur->_pLeft;
Node* right = cur->_pRight;
Node* parent = cur->_pParent;
Node* grendpa = parent->_pParent;
//更新cur左子树和parent的关系
if (left)
left->_pParent = parent;
parent->_pRight = left;
//更新cur和parent的关系
cur->_pLeft = parent;
if (GetRoot() == parent) {
//如果parent为根节点的话,需要链接_pHead
_pHead->_pParent = cur;
cur->_pParent = _pHead;
}
if (parent == grendpa->_pLeft)
grendpa->_pLeft = cur;
else
grendpa->_pRight = cur;
}
// 右单旋
void RotateR(Node* cur) {
Node* left = cur->_pLeft;
Node* right = cur->_pRight;
Node* parent = cur->_pParent;
Node* grendpa = parent->_pParent;
//更新cur右子树与parent的关系
if (right)
right->_pParent = parent;
parent->_pLeft = right;
//更新cur 和parent的关系
cur->_pRight = parent;
if (GetRoot() == parent) {
//如果parent为根节点,则需要更新_pHead的链接
_pHead->_pParent = cur;
cur->_pParent = _pHead;
}
if (parent == grendpa->_pLeft)
grendpa->_pLeft = cur;
else
grendpa->_pRight = cur;
}
4、红黑树迭代器的实现
红黑树的迭代器比较抽象的是需要实现 ++ 和 -- ,
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->_data;
}
Ptr operator->() {
return &_node->_data;
}
bool operator==(const Self& s) {
return _node == s->_node;
}
bool operator!=(const Self& s) {
return _node != s->_node;
}
Self& operator++() {
if (_node->_pRight)
_node = _node->_pRight;
else {
if (_node == _node->_pParent->_pLeft)
_node = _node->_pParent;
else if (_node == _node->_pParent->_pRight) {
while (_node != _node->_pParent->_pLeft) {
if (_node == _node->_pParent->_pParent) {
_node = _node->_pParent;
break;
}
_node = _node->_pParent;
}
}
}
return *this;
}
Self& operator--() {
if (_node->_pLeft)
_node = _node->_pLeft;
else {
if (_node == _node->_pParent->_pRight)
_node = _node->_pParent;
else if (_node == _node->_pParent->_pLeft) {
while (_node != _node->_pParent->_pRight) {
if (_node == _node->_pParent->_pParent) {
_node = _node->_pParent;
break;
}
_node = _node->_pParent;
}
}
}
return *this;
}
};
5、用自己实现的红黑树封装set
#include "RedBlackTree.hpp"
//封装set的大框架
namespace ltx {
template<class K>
class set {
public :
set():_bf(new RBTree<K, K, setKeyOfT>()) {}
typedef typename RBTree<K, K, setKeyOfT>::iterator iterator;
iterator begin() { return _bf.begin(); }
iterator end() { return _bf.end(); }
pair<iterator, bool> insert(const K& key) {
return _bf.Insert(key);
}
private :
struct setKeyOfT {
const K& operator()(const K& key) {
return key;
}
};
private :
RBTree<K, K, setKeyOfT> _bf;
};
}
6、用自己实现的红黑树封装map
#include "RedBlackTree.hpp"
//实现封装的大框架
namespace ltx {
template<class K, class V>
class map {
public:
map() :_bf(new RBTree<K, pair<K, V>, mapKeyOfT>()) {}
typedef typename RBTree<K, pair<K, V>, mapKeyOfT>::iterator iterator;
iterator begin() { return _bf.begin(); }
iterator end() { return _bf.end(); }
pair<iterator, bool> Insert(const pair<K, V>& kv) {
return _bf.Insert(kv);
}
V& operator[](const K& key) {
pair<iterator, bool> ret = Insert(make_pair(key, V()));
return ret.first->second;
}
private:
struct mapKeyOfT{
const K& operator()(const pair<K, V>& key) {
return key.first;
}
};
private:
RBTree<K, pair<K, V>, mapKeyOfT> _bf;
};
}