#pragma once
using namespace std;
#include<iostream>
typedef enum{RED=0,BLACK} Color;
template<typename Type>
struct RBTNode
{
Color color;
Type Key;
RBTNode* left;
RBTNode* right;
RBTNode* parent;
};
template<typename Type>
class RBTree
{
public:
RBTree()
{
Nil = BuyNode();
root = Nil;
Nil->color = BLACK;
}
~RBTree()
{
destroy(root);
delete Nil;
Nil = NULL;
}
void InOrder() { InOrder(root); }
bool Insert(const Type& value)
{
/*
插入
1.BST方式插入
2.调整平衡
备注:我们插入的节点除了树为空的情况下直接作为根节点染成黑色外,其他情况都是染成红色的,我们是先插入再调整的一个过程。
*/
RBTNode<Type>* pr = Nil;
RBTNode<Type>* s = root;
while (s != Nil)//相当于从根节点开始找,哪个节点能当你你传入的这个值的父节点
{
if (value == s->Key)//如果你要插入的这个值和这个点的值一样大,那么彻底无法插入
{
return false;
}
pr = s;
if (value < s->Key)
{
s = s->left;
}
else
{
s = s->right;
}
}
//根据while的条件,可以判断出while循环结束后,s一定是某一个空的叶子节点
s = BuyNode(value);//在这个空节点上,我们建立新的节点
if (pr == Nil)//如果pr为空,则说明当前创建的节点为根节点,因此要维护一下根节点的附属关系
{
root = s;
root->parent = pr;
}
else
{
if (value < pr->Key)
{
pr->left = s;
}
else
{
pr->right = s;
}
s->parent = pr;
}
Insert_Fixup(s);
return true;
}
void Remove(Type key)
{
RBTNode<Type>* t;
if ((t = Search(root, key)) != Nil)
{
Remove(t);//找到了就去除
}
else
{
cout << "ERROR::KEY IS NOT EXIST." << endl;//找不到就报错
}
}
void InOrderPrint()
{
InOrderPrint(root);
}
protected:
RBTNode<Type>* BuyNode(const Type& x = Type())
{
RBTNode<Type>* s = new RBTNode<Type>();
//static_assert(s != NULL);
s->color = RED;
s->left = s->right = s->parent = Nil;
s->Key = x;
return s;
}
void InOrder(RBTNode<Type>* root)
{
if (root!=Nil )
{
InOrder(root->left);
cout << root->Key << " ";
InOrder(root->right);
}
}
//一个旋转节点只和自己的右节点发生左旋,只和自己的左节点发生右旋
void LeftRotate(RBTNode<Type>* z)
{
/*左转,对z结点左转
zp zp
/ \
z z
/ \ / \
lz y lz y
/ \ / \
ly ry ly ry
左旋的整体思路:主要是对于旋转节点和其右子节点之间的旋转而这又需要参考旋转节点和其父节点之间的位置关系
1.首先先复制旋转节点的右子节点为y,先将y的左子节点设置为旋转节点的右节点,如果y的左子节点非空,则维护y的左子节点的parent成员
2.通过更改父节点的方式,将节点y放到了旋转节点的位置上,如果这一换换到了根节点上,那么维护更新一下根节点,如果没换到根节点上,根
据旋转节点是其父节点的左节点还是右节点,来更新节点y和旋转节点父节点的左右孩子关系
3.更新旋转节点与其右子节点的父子关系
整体思路:先将两节点格子的子节点的归属问题搞明白,再转换位置,并维护和根节点或父节点的关系,最终再将两节点的父子关系及逆行更新.
*/
RBTNode<Type>* y = z->right;
z->right = y->left;
if (y->left)
{
y->left->parent = z;
}
y->parent = z ->parent;
if (root == z)
{
root = y;
}
else if (z == z->parent->left)
{
z->parent->left = y;
}
else
{
z->parent->right = y;
}
y->left = z;
z -> parent = y;
}
void RightRotate(RBTNode<Type>* z)
{
/*
*右转,对z结点进行右转
zp zp
/ \
z z
/ \ / \
y rz y rz
/ \ / \
ly ry ly ry
思路只是和左旋稍微相反而已,首先考虑旋转节点的右子节点翻上来以后其子节点的归属问题,也就是先将右子节点的右子节点赋给旋转节点的左节点
再将旋转节点的右子节点连接到旋转节点的父节点上面,接着维护root,看看是否需要修改root,如果不需要,则根据旋转节点与其父节点的位置关系,设定
父节点的左节点或右节点为旋转节点的右子节点,以上操作结束后,我们维护一下旋转节点和旋转节点右节点的父子关系.
*/
RBTNode<Type>* y = z->left;
z->left = y->right;
if (y->right)
{
y->right->parent = z;
}
y->parent = z->parent;
if (root == z)
{
root = y;
}
else if (z == z->parent->left)
{
z->parent->left = y;
}
else
{
z->parent->right = y;
}
y->right = z;
z->parent = y;
}
void Insert_Fixup(RBTNode<Type>* s)
{
/*
我们这里讨论的是新节点不为根节点的情况
一、新插入节点的父节点是黑色节点,则不用调整
二、新插入节点的父节点为红色
1.该父节点的兄弟节点也是红色节点
2.该父节点的兄弟节点是黑色节点
2.1插入节点->父节点->爷节点位置呈/
2.2插入节点->父节点->爷节点的位置呈<
2.3插入节点->父节点->爷节点的位置呈\
2.4插入节点->父节点->爷节点的位置呈>*/
RBTNode<Type>* uncle;
while (s->parent->color == RED)//这里很简单:我们最核心的诉求就是新插入的这个节点不要和它的父节点都是红节点而已
{
if (s->parent == s->parent->parent->left)//当我们想要具体的知道叔伯节点时就已经要开始分情况了
{
uncle = s->parent->parent->right;
if (uncle->color == RED)//如果叔伯节点为红色
{
s->parent->color = BLACK;
uncle->color = BLACK;
s->parent->parent->color = RED;
s = s->parent->parent;
}
else//如果书伯节点为黑色或不存在叔伯节点
{
if (s == s->parent->right)//插入节点->父节点->爷节点呈<,则先进行一次左旋,再进行右旋
{
s = s->parent;
LeftRotate(s);
}
//如果插入节点->父节点->爷节点呈/则直接到这里改变颜色然后右旋即可
s->parent->color = BLACK;
s->parent->parent->color = RED;
RightRotate(s->parent->parent);//这里提示了我们,无论左旋还是右旋,我们所说的旋转节点全部都是
}
}
else
{
if (s->parent == s->parent->parent->right)//父节点是爷节点的右节点
{
uncle = s->parent->parent->left;
if (uncle->color == RED)
{
s->parent->color = BLACK;
uncle->color = BLACK;
s->parent->parent->color = RED;
s = s->parent->parent;
}
else//同样的还是叔伯节点为空或者黑节点时
{
if (s == s->parent->left)
{
s = s->parent;
RightRotate(s);
}
s->parent->color = BLACK;
s->parent->parent->color = RED;
LeftRotate(s->parent->parent);
}
}
}
}
root->color = BLACK;
/*我们一切规则的根本都是说黑节点不能失去平衡, 因此根节点是可以随意设置为黑色的,
根节点设置为黑色,整个RBTree的平衡完全没有影响,此外while循环的终止条件的到来也是
因为这个操作,到了某一次,s节点向上传递成根节点子节点时,这里将根节点设置为黑,则上面一判断就跳出结束了
*/
}
RBTNode<Type>* Search(RBTNode<Type>* root, Type key) const
{
if (root == Nil) return Nil;
if (root->Key == key)
{
return root;
}
if (key < root->Key)
{
return Search(root->left,key);
}
else
{
return Search(root->right,key);
}
}
void Transplant(RBTNode<Type>* u, RBTNode<Type>* v)
{
/*这是一个简答的变换,u为父节点,v为子节点 ,主要是给去除节点的时候用的,主要是用来建立子节点和爷节点的关系*/
//注意!!!!这里并没有对中间的这个父节点u进行任何更改
if (u->parent == Nil)
{
root = v;
}
else if (u == u->parent->left)
{
u->parent->left = v;
}
else
{
u->parent->right = v;
}
v->parent = u->parent;
}
RBTNode<Type>* Minimum(RBTNode<Type>* x)
{/*找到最小节点,就是个递归往左找的过程*/
if (x->left == Nil)
{
return x;
}
return Minimum(x->left);
}
void Remove(RBTNode<Type>* z)
{
/*这个函数主要就是一个二叉搜索树的删除算法,当被删除点的子节点数小于等于1时,直接维护一个x并且,直接进行替换即可
代码中的x代表这替换被删除节点的那个节点的*/
RBTNode<Type>* x = Nil;
RBTNode<Type>* y = z;
Color ycolor = y->color;
if (z->left == Nil)
{
x = z->right;
Transplant(z, z->right);
}
else if(z->right==Nil)
{
x = z->left;
Transplant(z, z->left);
}
/*上面这两个if 和 else if覆盖了正常的二叉搜索树删除算法中被删除节点只有一个子节点或者是叶子节点的情况,
固然像你想象的那样,左节点没有并不代表右节点就有,但是我们仍然可以使用右节点来替换被删除节点,只不过
这样会构成一种叫双黑节点的东西*/
else
{
//这个就很容易理解了,当被删除节点两个节点都存在时,我们可以选取左子树中最大的节点来替换它,也可以选
//取右子树中最小的节点替代他,这里我们使用的是右子树最小节点的方法
y = Minimum(z->right);
ycolor = y->color;
x = y->right;
if (y->parent == z)//这里的if else也看懂了,当y就是z的右节点时,它想替换z的位置就不用继承什么z的右节点了,相反如果不是
//z的直接右节点,我们的节点搬上去就需要把z节点的左右节点都继承上
{
//x->parent = y;
cout << "写你吗呢" << endl;
}
else
{
Transplant(y, y->right);
y->right = z->right;
y->right->parent = y;
}
Transplant(z, y);
y->left = z->left;
z->left->parent = y;
y->color = z->color;
}
if (ycolor == BLACK)
{
Remove_Fixup(x);
}
}
void Remove_Fixup(RBTNode<Type>* x)
{
while (x != root && x->color == BLACK)
{
if (x == x->parent->left)
{
RBTNode<Type>* w = x->parent->right;
if (w->color == RED)
{
w->color = BLACK;
x->parent->color = RED;
LeftRotate(x->parent);
w = x->parent->right;
}
if (w->left->color == BLACK && w->right->color == BLACK)
{
w->color = RED;
x = x->parent;
}
else
{
if (w->right->color == BLACK)
{
w->color = RED;
w->left->color = BLACK;
RightRotate(w);
w = x->parent->right;
}
w->color = w->parent->color;
w->parent->color = BLACK;
w->right->color = BLACK;
LeftRotate(x->parent);
x = root;
}
}
else
{
RBTNode<Type>* w = x->parent->left;
if (w->color == RED)
{
w->parent->color = RED;
w->color = BLACK;
RightRotate(x->parent);
w = x->parent->left;
}
if (w->right->color == BLACK && w->left->color == BLACK)
{
w->color = RED;
x = x->parent;
}
else
{
if (w->left->color == BLACK)
{
w->right->color = BLACK;
w->color = RED;
LeftRotate(w);
w = x->parent->left;
}
w->color = x->parent->color;
x->parent->color = BLACK;
w->left->color = BLACK;
RightRotate(x->parent);
x = root;
}
}
}
x->color = BLACK;
}
void destroy(RBTNode<Type>* root)
{
if (root == Nil) return;
if (root->left != Nil) destroy(root->left);
if (root->right != Nil) destroy(root->right);
delete root;
root = NULL;
}
void InOrderPrint(RBTNode<Type>* node)
{
if (node == Nil) return;
if (node->left != NULL)
{
InOrderPrint(node->left);
}
cout << node->Key << "(" << ((node->color == BLACK) ? "BLACK" : "RED") << ")" << " ";
if (node->right != Nil)
{
InOrderPrint(node->right);
}
}
public:
RBTNode<Type>* root;
RBTNode<Type>* Nil=nullptr;
};
手撕红黑树--保证能跑
于 2022-05-26 13:27:04 首次发布