红黑树
一棵红黑树是满足下面性质的二叉搜索树:
1,每个结点或是红色,或是黑色的.
2,根节点必须是黑色的.
3,每个分支的最后一个结点是黑色.
4,如果一个结点是红色的,则它的两个子结点必然都是黑色.
5,对每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点.
#include <iostream>
#include <memory>
#include <type_traits>
//注明:以nullptr表示树的尾部.
enum class Color : int{
Red,
Black
};
template<typename T>
class Node{
public:
T data;
Color color;
Node<T>* left;
Node<T>* right;
Node<T>* parent;
public:
Node(Color clir = Color::Black):color(clr),parent(nullptr),left(nullptr),right(nullptr){}
template<typename Ty>
Node(const Ty& dt, Color clr = Color::Black, Node<T>* lh=nullptr, Node<T>* rh=nullptr, Node<T>* pr=nullptr);
Node(const T& dt, Color clr=Color::Black, Node<T>* lh=nullptr, Node<T>* rh=nullptr, Node<T>* pr=nullptr);
~Node()=default;
};
template<typename T>
template<typename Ty>
Node<T>::Node(const Ty& dt, Color clr, Node<T>* lh, Node<T>* rh, Node<T>* pr)
:data(dt),
color(clr),
left(lh),
right(rh),
parent(pr)
{
//
}
template<typename T>
Node<T>::Node(const T& dt, Color clr, Node<T>* lh, Node<T>* rh, Node<T>* pr)
:data(dt),
color(clr),
left(lh),
right(rh),
parent(pr)
{
//
}
template<typename T>
class RBTree{
private:
Node<T>* root;
void leftRotate(Node<T>* rt, Node<T>* x); //在结点x上做左旋.
void rightRotate(Node<T>* rt, Node<T>* y); //右旋在结点y上做右旋.
void insertFixUp(Node<T>* rt, Node<T>* z); //插入修正保持红黑树的特性.
void transPlant(Node<T>* first, Node<T>* second); //辅助删除结点.
void deleteNode(Node<T>* node); //删除一个结点.
Node<T>* minmumSubNode(Node<T>* node); //返回node中最小的子结点.
void deleteFixUp(Node<T>* node); //删除修正,在删除一个红黑树结点后对红黑树进行修正保证红黑树的性质.
//----------辅助函数-----------
inline Node<T>* getParent(Node<T>* node) //获得一个函数的父结点.
{
return node->parent;
}
inline Node<T>* getGParent(Node<T>* node); //获得一个函数的父结点的父结点.
{
return (node->parent)->parent;
}
public:
template<typename ...Args>
RBTree(Args&&... parameters);
RBTree();
~RBTree();
};
//左旋:
template<typename T>
void RBTree<T>::leftRotate(Node<T>* rt, Node<T>* x)
{
Node<T>* y = x->right;
x->right = y->left;
if(y->left != nullptr){
y->left->parent = x;
}
y->parent = x->parent;
if(y->parent == nullptr){
rt = y;
}else if(x == x->parent->left){
x->parent->left = y;
}else{
x->parent->right = y;
}
y->left = x;
x->parent = y;
}
// 7 7
// / \ / \
// 4 11(x) 4 18(y)
// / \ / \ leftRotate(x) / / \
// 3 6 9 18(y) ---------------> 3 11(x) 19
// / / \ <--------------- / / \ \
// 2 14 19 rightRotate(y) 2 9 14 22
// / \ \ / \ /
// 12 17 22 12 17 20
// /
// 20
//右旋:
template<typename T>
void RBTree<T>::rightRotate(Node<T>* rt, Node<T>* y)
{
Node<T>* x = y->left;
y->left = x->right;
if(x->right != nullptr){
x->right->parent = y;
}
x->parent = y->parent;
if(y->parent == nullptr){
rt = x;
}else if(y == y->parent->left){
y->parent->left = y;
}else{
y->parent->left = x;
}
x->right = y;
y->parent = x;
}
//插入修正.
template<typename T>
void RBTree<T>::insertFixUp(Node<T>* rt, Node<T>* z)
{
Node<T>* zParent = (this->getParent)(z);
Node<T>* zGParent = (this->getGParent)(z);
while(zParent->color == Color::Red){
if(zParent == zGParent->left){
Node<T>* y = zGParent->right;
if(y->color == Color::Red){
zParent->color = Color::Black;
y->color = Color::Black;
zGParent->color = Color::Red;
z = zGParent;
zParent = (this->getParent)(z);
zGParent = (this->getGParent)(z);
}else if(z == zParent->right){
z = (this->getParent)(z);
this->leftRotate(rt, z);
}
(this->getParent)(z)->color = Color::Black;
(this->getGParent)(z)->color = Color::Red;
this->rightRotate(rt, this->getGParent(z));
}else if(zParent == zGParent->right){
Node<T>* y = zGParent->left;
if(y->color == Color::Red){
zParent->color = Color::Black;
y->color = Color::Blac;
zGParent->color = Color::Red;
z = zGParent;
zParent = (this->getParent)(z);
zGParent = (this->getGParent)(z);
}else if(z == zParent->left){
z = (this->getParent)(z);
this->rightRotate(rt, z);
}
(this->getParent)(z)->color = Color::Black;
(this->getGParent)(z)->color = Color::Red;
this->rightRotate(rt, this->getGParent(z));
}
}
rt->color = Color::Black;
}
//辅助删除结点. 借鉴了二叉搜索树的transPlant.
//1, 如果first结点是树根,那么就更新红黑树的根结点为.
//2, 如果first为其父结点的左结点的情况.
//3, 如果fist为其父亲右结点的情况.
template<typename T>
void RBTree<T>::transPlant(Node<T>* first, Node<T>* second)
{
if(first->parent == nullptr){
this->root = first;
}else if(first == first->parent->left){
first->parent->left = second;
}else{
first->parent->right = second;
}
first->parent = second->parent;
}
//辅助删除结点. 借鉴了二叉搜索树的minmum.
//主要作用是把被删除的结点的2个子结点连接到被删除结点的父结点下面.
template<typename T>
Node<T>* RBTree<T>::minimumSubNode(Node<T>* node)
{
Node<T> tempNode = nullptr;
if(node != nullptr){
while(node->left != nullptr){
tempNode = node->left;
}
}
return tempNode;
}
//删除一个结点.
template<typename T>
void RBTree<T>::deleteNode(Node<T>* node)
{
Node<T>* tempNodeOne = node;
Node<T>* tempNodeTwo = nullptr;
Color tempColor = tempNode->color;
if(node->left == nullptr){
tempNodeTwo = node->right;
this->transPlant(node, node->right);
}else if(node->right == nullptr){
tempNodeTwo = node->left;
this->transPlant(node, node->left);
}else{
tempNodeOne = minimumSubNode(node->right);
tempColor = tempNodeOne->color;
tempNodeTwo = tempNodeOne->right;
if(tempNodeOne->parent == node){
tempNodeTwo->parent = tempNodeOne;
}else{
this->transPlant(tempNodeOne, tempNodeOne->right);
tempNodeOne->right = node->right;
tempNodeOne->right->parent = tempNodeOne;
}
this->transPlant(node, tempNodeOne);
tempNodeOne->left = node->left;
tempNodeOne->left->parent = tempNodeOne;
tempNodeOne->color = node->color;
}
if(tempColor == Color::Black){
}
}
//用于在删除一个结点过后修正红黑树的性质.
template<typename T>
void RBTree<T>::deleteFixUp(Node<T>* node)
{
Node<T>* tempNodeOne = nullptr;
while(x != this->root && node->color == Color::Black){
if(node == node->parent->left){
tempNodeOne = node->parent->right;
//case 1:
if(tempNodeOne->color == Color::Red){
tempNodeOne->color = Black;
this->leftRotate(this->root, node->parent);// notice! left-rotate!
tempNodeOne = node->parent->right;
}
//case 2:
if(tempNodeOne->left->color == Color::Black && tempNodeOne->right->color == Black){
tempNodeOne->color = Color::Red;
node = node->parent;
//case 3:
}else if(tempNodeOne->right->color == Color::Black){
tempNodeOne->left->color = Color::Black;
tempNodeOne->color = Color::Red;
this->rightRotate(this->root, tempNodeOne);
tempNodeOne = node->parent->right;
}
}else{
tempNodeOne = node->parent->left;
}
}
}