#include <iostream>
#include <iomanip>
using namespace std;
#define RED 0 //红色结点
#define BLACK 1 //黑色结点
template<class T>
class RbTreeNode
{
public:
unsigned int color;
T key;
RbTreeNode *left;
RbTreeNode *right;
RbTreeNode *parent;
RbTreeNode(const int &value = RED, T c = -1, RbTreeNode<T> *l = NULL, RbTreeNode<T> *r = NULL, RbTreeNode<T> *p = NULL):
color(value), key(c), left(l), right(r), parent(p){}
};
template<class T>
class RbTree
{
private:
RbTreeNode<T> *Root;
public:
RbTreeNode<T> *nil;
RbTree();
~RbTree();
//前中后序遍历
void preOrder();
void inOrder();
void postOrder();
//查找红黑树树x中键值为key的结点
RbTreeNode<T>* ssearch(T key);
//查找最小结点,并返回值为根结点
T minimum();
//查找最大结点,并返回值为根结点
T maximum();
//将结点(key为键值)插入红黑树中
void iinsert(T key);
//删除结点(key为键值)
void ddelete(T key);
//销毁红黑树
void destroy();
//打印红黑树
void print();
private:
//前中后序遍历
void preOrder(RbTreeNode<T>* tree) const;
void inOrder(RbTreeNode<T>* tree) const;
void postOrder(RbTreeNode<T>* tree) const;
//查找红黑树x中键值为key的结点
RbTreeNode<T>* ssearch(RbTreeNode<T>* x, T key) const;
//查找最小结点,并返回值为根结点
RbTreeNode<T>* minimum(RbTreeNode<T>* x);
//查找最大结点,并返回值为根结点
RbTreeNode<T>* maximum(RbTreeNode<T>* x);
//找结点x的前驱结点。即,查找"红黑树中数据值小于该结点"的"最大结点"。
RbTreeNode<T>* predecessor(RbTreeNode<T>* x);
//找结点(x)的后继结点。即,查找"红黑树中数据值大于该结点"的"最小结点"。
RbTreeNode<T>* successor(RbTreeNode<T>* x);
//左旋
void Left_rotation(RbTreeNode<T>* &root, RbTreeNode<T> *x);
//右旋
void Right_rotation(RbTreeNode<T>* &root, RbTreeNode<T> *y);
//红黑树插入修正
void iinsert_fixup(RbTreeNode<T>* &root, RbTreeNode<T> *x);
//将结点x插入到红黑树中
void iinsert(RbTreeNode<T>* &r, RbTreeNode<T>* &x);
//红黑树删除修正
void delete_fixup(RbTreeNode<T>* &root, RbTreeNode<T> *x);
//移植操作
void Rb_transplant(RbTreeNode<T>* &root, RbTreeNode<T>* &u, RbTreeNode<T>* &v);
//删除红黑树中的结点(键值为key)
void ddelete(RbTreeNode<T>* &root, RbTreeNode<T> *x);
//销毁红黑树
void destroy(RbTreeNode<T>* &tree);
//打印红黑树
void print(RbTreeNode<T>* tree, T key, int d);
};
template<class T>
RbTree<T>::RbTree()
{
nil = new RbTreeNode<T>(BLACK, -1, nil, nil, nil);
Root = nil;
}
template<class T>
RbTree<T>::~RbTree()
{
destroy(Root);
delete nil;
}
//前序遍历
template<class T>
void RbTree<T>::preOrder(RbTreeNode<T>* tree) const
{
if(tree != nil)
{
cout << tree->key << " ";
preOrder(tree->left);
preOrder(tree->right);
}
}
template<class T>
void RbTree<T>::preOrder()
{
preOrder(Root);
}
//中序遍历
template<class T>
void RbTree<T>::inOrder(RbTreeNode<T>* tree) const
{
if(tree != nil)
{
inOrder(tree->left);
cout << tree->key << " ";
inOrder(tree->right);
}
}
template<class T>
void RbTree<T>::inOrder()
{
inOrder(Root);
}
//后序遍历
template<class T>
void RbTree<T>::postOrder(RbTreeNode<T>* tree) const
{
if(tree != nil)
{
postOrder(tree->left);
postOrder(tree->right);
cout << tree->key << " ";
}
}
template<class T>
void RbTree<T>::postOrder()
{
postOrder(Root);
}
template<class T>
RbTreeNode<T>* RbTree<T>::ssearch(RbTreeNode<T>* x, T key) const
{
if(x == nil || x->key == key)
{
return x;
}
if(key < x->key)
{
return ssearch(x->left, key);
}
else
{
return ssearch(x->right, key);
}
}
template<class T>
RbTreeNode<T>* RbTree<T>::ssearch(T key)
{
ssearch(Root, key);
}
//查找最小结点,并返回值为根结点
template<class T>
RbTreeNode<T>* RbTree<T>::minimum(RbTreeNode<T>* tree)
{
if(tree == nil)
{
return nil;
}
while(tree->left != nil)
{
tree = tree->left;
}
return tree;
}
template<class T>
T RbTree<T>::minimum()
{
RbTreeNode<T>* p = minimum(Root);
if(p != nil)
{
return p->key;
}
return T(NULL);
}
//查找最大结点,并返回值为根结点
template<class T>
RbTreeNode<T>* RbTree<T>::maximum(RbTreeNode<T>* tree)
{
if(tree == nil)
{
return nil;
}
while(tree->right != nil)
{
tree = tree->right;
}
return tree;
}
template<class T>
T RbTree<T>::maximum()
{
RbTreeNode<T>* p = maximum(Root);
if(p != nil)
{
return p->key;
}
return T(NULL);
}
//找结点x的前驱结点即,查找"红黑树中数据值小于该结点"的"最大结点"。
template<class T>
RbTreeNode<T>* RbTree<T>::predecessor(RbTreeNode<T>* x)
{
// 如果x存在左孩子,则"x的前驱结点"为 "以其左孩子为根的子树的最大结点"。
if(x->left != nil)
{
return maximum(x->left);
}
// 如果x没有左孩子。则x有以下两种可能:
// 1. x是"一个右孩子",则"x的前驱结点"为 "它的父结点"。
// 2. x是"一个左孩子",则查找"x的父结点,并且该父结点要为右孩子",找到的这个"父结点的父结点"就是"x的前驱结点"。
RbTreeNode<T> *p = x->parent;
while(x != p->right && p)
{
x = p;
p = p->parent;
}
return p;
}
//找结点(x)的后继结点。即,查找"红黑树中数据值大于该结点"的"最小结点"。
template<class T>
RbTreeNode<T>* RbTree<T>::successor(RbTreeNode<T>* x)
{
// 如果x存在右孩子,则"x的后继结点"为 "以其右孩子为根的子树的最小结点"。
if(x->right != nil)
{
return minimum(x->right);
}
// 如果x没有右孩子。则x有以下两种可能:
// 1. x是"一个左孩子",则"x的后继结点"为 "它的父结点"。
// 2. x是"一个右孩子",则查找"x的父结点,并且该父结点要为左孩子",找到的这个"父结点的父结点"就是"x的后继结点"。
RbTreeNode<T> *p = x->parent;
if(p->left != x && p)
{
x = p;
p = p->parent;
}
return p;
}
//左旋示意图(对结点x进行左旋):
// px px
// / /
// x p
// / \ --(左旋)--> / \
// lx p x rp
// / \ / \
// lp rp lx lp
template<class T>
void RbTree<T>::Left_rotation(RbTreeNode<T>* &root, RbTreeNode<T> *x)
{
RbTreeNode<T> *p = x->right;
x->right = p->left;
if(p->left != nil)
{
p->left->parent = x;
}
p->parent = x->parent;
if(x->parent == nil)
{
root = p;
}
else
{
if(x->parent->left == x)
{
x->parent->left = p;
}
else
{
x->parent->right = p;
}
}
x->parent = p;
p->left = x;
}
// 右旋示意图(对结点y进行左旋):
// py py
// / /
// y p
// / \ --(右旋)--> / \
// p ry lp y
// / \ / \
// lp rp rp ry
template<class T>
void RbTree<T>::Right_rotation(RbTreeNode<T>* &root, RbTreeNode<T> *y)
{
RbTreeNode<T> *p = y->left;
y->left = p->right;
if(p->right != nil)
{
p->right->parent = y;
}
p->parent = y->parent;
if(y->parent != nil)
{
if(y->parent->left = y)
{
y->parent->left = p;
}
else
{
y->parent->right = p;
}
}
else
{
root = p;
}
p->right = y;
y->parent = p;
}
//红黑树插入修正函数
// 在向红黑树中插入结点之后(失去平衡),再调用该函数;
// 目的是将它重新塑造成一颗红黑树。
/*
总共有四种情景:
1:红黑树为空树时 ——> 把插入结点作为根节点,并把颜色设置为黑色。
2:插入结点的key已存在 ——> 把插入结点设为当前结点的颜色,更新当前结点的值为插入结点的值。
3:插入结点的父结点为黑色结点 ——> 直接插入。
4:插入结点的父结点为红色结点
4.1:叔叔结点存在且为红色结点 ——> 将父亲结点和叔叔结点设为黑色,祖父结点设为红色,将祖父结点设为插入结点。
4.2:叔叔结点不存在或为黑色结点,并且插入结点的父亲结点是祖父结点的左孩子结点
4.2.1:插入结点是其父亲结点的左孩子结点 ——> 将父亲结点设为黑色,将祖父结点设为红色,对祖父结点进行右旋。
4.2.2:插入结点是其父亲结点的右孩子结点 ——> 对父亲结点进行左旋,将父亲结点设为插入结点得到4.2.1,进行4.2.1的操作。
4.3:叔叔结点不存在或为黑色结点,并且插入结点的父亲结点是祖父结点的右孩子结点
4.3.1:插入结点是其父亲结点的右孩子结点 ——> 将父亲结点设为黑色,将祖父结点设为红色,对祖父结点进行左旋。
4.3.2:插入结点是其父亲结点的左孩子结点 ——> 对父亲结点进行右旋,将父亲结点设为插入结点得到4.3.1,进行4.3.1的操作。
*/
template<class T>
void RbTree<T>::iinsert_fixup(RbTreeNode<T>* &root, RbTreeNode<T> *x)
{
RbTreeNode<T> *parent, *gparent;
while((parent = x->parent) && parent->color == RED) //父结点存在且为红色
{
gparent = parent->parent;
if(gparent->left == parent) //父结点为祖父结点的左孩子
{
RbTreeNode<T> *uncle = gparent->right;
//4.1:叔叔结点存在且为红色结点 ——> 将父亲结点和叔叔结点设为黑色,祖父结点设为红色,将祖父结点设为插入结点
if(uncle && uncle->color == RED)
{
parent->color = BLACK;
uncle->color = BLACK;
gparent->color = RED;
x= gparent;
continue;
}
//4.2.2:插入结点是其父亲结点的右孩子结点 ——> 对父亲结点进行左旋,将父亲结点设为插入结点得到4.2.1,进行4.2
if(parent->right == x)
{
RbTreeNode<T> *t;
Left_rotation(root, parent);
t = parent;
parent = x;
x = t;
}
//4.2.1:插入结点是其父亲结点的左孩子结点 ——> 将父亲结点设为黑色,将祖父结点设为红色,对祖父结点进行右旋。
parent->color = BLACK;
gparent->color = RED;
Right_rotation(root,gparent);
}
else //父结点为祖父结点的右孩子
{
RbTreeNode<T> *uncle = gparent->left;
//4.1:叔叔结点存在且为红色结点 ——> 将父亲结点和叔叔结点设为黑色,祖父结点设为红色,将祖父结点设为插入结
if(uncle && uncle->color == RED)
{
parent->color = BLACK;
uncle->color = BLACK;
gparent->color = RED;
x = gparent;
continue;
}
//4.3.2:插入结点是其父亲结点的左孩子结点 ——> 对父亲结点进行右旋,将父亲结点设为插入结点得到4.3.1,进行4.3.1的操作。
if(x == parent->left)
{
RbTreeNode<T> *t;
Right_rotation(root,parent);
t= parent;
parent = x;
x = t;
}
//4.3.1:插入结点是其父亲结点的右孩子结点 ——> 将父亲结点设为黑色,将祖父结点设为红色,对祖父结点进行左旋。
parent->color = BLACK;
gparent->color = RED;
Left_rotation(root, gparent);
}
}
root->color = BLACK;
}
//将结点x插入到红黑树中
template<class T>
void RbTree<T>::iinsert(RbTreeNode<T>* &r, RbTreeNode<T>* &x)
{
RbTreeNode<T> *y = nil;
RbTreeNode<T> *z = r;
while(z != nil)
{
y = z;
if(x->key < z->key)
{
z = z->left;
}
else
{
z = z->right;
}
}
x->parent = y;
if(y == nil)
{
r = x;
}
else if(x->key < y->key)
{
y->left = x;
}
else
{
y->right = x;
}
x->left = nil;
x->right = nil;
iinsert_fixup(r, x);
}
template<class T>
void RbTree<T>::iinsert(T key)
{
RbTreeNode<T> *z = nil;
if((z = new RbTreeNode<T>(RED,key,nil, nil,nil)) == nil)
{
return;
}
iinsert(Root, z);
}
/*
三种删除结点的情景
我们以下将删除结点称为z,替代z位置的结点称为y(y为z的后继结点或z结点本身)
1:如果y是叶子结点,则直接删除即可。
2:如果y只有一个孩子,则将父结点的指针指向它的孩子。
3:如果y有两个孩子,则可以找它的后继,将值覆盖过来,之后情况转变成删除后继结点,回到1和2。
当删除结点后,若待删除结点为红色时,红黑树性质仍然保持
1:树中的黑高没有改变。
2:不存在两个相邻的红结点。因为待删除结点在树中占据了删除结点的位置,考虑到删除结点的颜色,树中待删除结点的新位置不可能
有两个相邻的红结点。另外,如果,待删除结点不是删除结点的右孩子,则待删除结点的原右孩子代替待删除结点。如果待删除结点
是红色,则它的右孩子一定是黑色,因此用右孩子来代替不可能使两个红结点相邻。
3:如果待删除结点是红色,就不可能是根结点,所以根结点仍旧为黑色。
这样当待删除结点为黑色结点时进行修复
约定: x ——> 代替y位置的结点
p ——> x的父结点
w ——> x的兄弟结点
wl ——> w的左子结点
wr ——> w的右子结点
1:x是p的左子结点
1.1:w是红色结点 ——> w设为黑色,p设为红色,对p左旋,得到1.2进行处理
1.2:w是黑色结点
1.2.1:wr是红结点,wl任意颜色 ——> w设为p颜色,p设为黑色,wr设为黑色,对p进行左旋
1.2.2:wr是黑结点,wl是红结点 ——> w设为红色,wl设为黑色,对w进行右旋,得到1.2.1处理
1.2.3:wr与wl都为黑结点 ——> w设为红色,p作为新的代替待删除结点的结点,重新进行修复处理
2:x是p的右子结点
2.1:w是红结点 ——> w设为黑色,p设为红色,对p右旋,得到2.2进行处理
2.2:w是黑结点
2.2.1:wl是红结点,wr任意颜色 ——> w设为p颜色,p设为黑色,wl设为黑色,对p进行右旋
2.2.2:wl是黑结点,wr是红结点 ——> w设为红色,wr设为黑色,对w进行左旋,得到2.2.1处理
2.2.3:wr与wl都为黑结点 ——> w设为红色,p作为新的代替待删除结点的结点,重新进行修复处理
*/
template<class T>
void RbTree<T>::delete_fixup(RbTreeNode<T>* &root, RbTreeNode<T> *x)
{
while(x != root && x->color == BLACK)
{
if(x == x->parent->left) //1:x是p的左子结点
{
RbTreeNode<T> *w = x->parent->right;
//1.1:w是红色结点 ——> w设为黑色,p设为红色,对p左旋,得到1.2进行处理
if(w->color == RED)
{
w->color = BLACK;
x->parent->color = RED;
Left_rotation(root, x->parent);
w = x->parent->right;
}
//1.2:w是黑色结点
//1.2.3:wr与wl都为黑结点 ——> w设为红色,p作为新的代替待删除结点的结点,重新进行修复处理
if(w->left->color == BLACK && w->right->color == BLACK)
{
w->color = RED;
x = x->parent;
}
else
{
//1.2.2:wr是黑结点,wl是红结点 ——> w设为红色,wl设为黑色,对w进行右旋,得到1.2.1处理
if(w->right->color == BLACK)
{
w->color = RED;
w->left->color = BLACK;
Right_rotation(root, w);
w = x->parent->right;
}
//1.2.1:wr是红结点,wl任意颜色 ——> w设为p颜色,p设为黑色,wr设为黑色,对p进行左旋
w->color = x->parent->color;
x->parent->color = BLACK;
w->right->color = BLACK;
Left_rotation(root, x->parent);
x = root;
}
}
else //2:x是p的右子结点
{
RbTreeNode<T> *w = x->parent->left;
//2.1:w是红结点 ——> w设为黑色,p设为红色,对p右旋,得到2.2进行处理
if(w->color == RED)
{
w->color = BLACK;
x->parent->color = RED;
Right_rotation(root, x->parent);
w = x->parent->left;
}
//2.2:w是黑结点
//2.2.3:wr与wl都为黑结点 ——> w设为红色,p作为新的代替待删除结点的结点,重新进行修复处理
if(w->left->color == BLACK && w->right->color == BLACK)
{
w->color = RED;
x = x->parent;
}
else
{
//2.2.2:wl是黑结点,wr是红结点 ——> w设为红色,wr设为黑色,对w进行左旋,得到2.2.1处理
if(w->left->color == BLACK)
{
w->color = RED;
w->right->color = BLACK;
Left_rotation(root, w);
w = x->parent->left;
}
//2.2.1:wl是红结点,wr任意颜色 ——> w设为p颜色,p设为黑色,wl设为黑色,对p进行右旋
w->color = x->parent->color;
x->parent->color = BLACK;
w->left->color = BLACK;
Right_rotation(root, x->parent);
x = root;
}
}
}
x->color = BLACK;
}
template<class T>
void RbTree<T>::Rb_transplant(RbTreeNode<T>* &root, RbTreeNode<T>* &u, RbTreeNode<T>* &v)
{
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;
}
template<class T>
void RbTree<T>::ddelete(RbTreeNode<T>* &root, RbTreeNode<T> *z)
{
RbTreeNode<T> *y = z; //替代z位置的结点称为y
RbTreeNode<T> *x = z; //代替y位置的结点
int color = y->color;
if(z->left == nil) //如果删除结点为叶子结点直接删除或没有左孩子时让父指针指向右孩子
{
x = z->right;
Rb_transplant(root, z, z->right);
}
else if(z->right == nil) //如果删除结点为叶子结点直接删除或没有右孩子时让父指针指向左孩子
{
x = z->left;
Rb_transplant(root, z, z->left);
}
else //删除结点有两个孩子
{
y = successor(z); //y变为删除结点的后继结点
color = y->color;
x = y->right;
if(y->parent == z) //y恰好为删除结点的孩子结点
{
x->parent = y;
}
else //y不为删除结点的孩子结点
{
Rb_transplant(root, y, y->right); //先将y的父指针指向右孩子(将x变为y的位置)
y->right = z->right;
y->right->parent = y; //y与删除结点的右孩子连接
}
Rb_transplant(root, z, y); //将删除结点父指针指向y
y->left = z->left;
y->left->parent = y; //y与删除结点的左孩子连接
y->color = z->color;
}
if(color == BLACK) //y为黑色结点需要进行修复
{
delete_fixup(root, x);
}
}
template<class T>
void RbTree<T>::ddelete(T key)
{
RbTreeNode<T> *z = nil;
if((z = ssearch(key)) == nil)
{
return;
}
ddelete(Root, z);
}
template<class T>
void RbTree<T>::print(RbTreeNode<T>* tree, T key, int d)
{
if(tree != nil)
{
if(d == 0)
{
cout << setw(2) << tree->key << " is root";
if(tree->color == 0)
{
cout << "(RED" << ")" << endl;
}
else
{
cout << "(BLACK" << ")" << endl;
}
}
else
{
cout << setw(2) << tree->key << " is " << setw(2) << key << "'s" << setw(12) << (d == 1 ? "right child" : "left child");
if(tree->color == 0)
{
cout << "(RED" << ")" << endl;
}
else
{
cout << "(BLACK" << ")" << endl;
}
}
print(tree->left, tree->key, -1);
print(tree->right, tree->key, 1);
}
}
template<class T>
void RbTree<T>::print()
{
if(Root != nil)
{
print(Root, Root->key, 0);
}
}
template <class T>
void RbTree<T>::destroy(RbTreeNode<T>* &tree)
{
if (tree == nil)
{
return ;
}
if (tree->left != nil)
{
destroy(tree->left);
}
if (tree->right != nil)
{
destroy(tree->right);
}
delete tree;
}
template <class T>
void RbTree<T>::destroy()
{
destroy(Root);
}
int main()
{
int a, n;
RbTree<int>* tree = new RbTree<int>();
cout << "请输入结点个数:";
cin >> n;
cout << "请输入结点的键值:";
for(int i = 1; i <= n; i++)
{
cin >> a;
tree->iinsert(a);
}
cout << "\n前序遍历:";
tree->preOrder();
cout << "\n中序遍历:";
tree->inOrder();
cout << "\n后序遍历:";
tree->postOrder();
cout << endl;
cout << "最小值:" << tree->minimum() << endl;
cout << "最大值:" << tree->maximum() << endl;
cout << "整棵树:" << endl;
tree->print();
int x;
cout << "\n请输入要删除的结点的结点值:";
cin >> x;
tree->ddelete(x);
cout << "\n删除" << x << "结点后整棵树:";
tree->print();
tree->destroy();
return 0;
}
红黑树c++类模板代码
于 2022-01-15 10:53:53 首次发布