红黑树实现
插入规则
当添加一个节点时旋转和颜色变换规则:
当前结点的父亲是红色,且它的祖父结点的另一个子结点也就是uncle节点也是红色就需要变色。
1.把父节点设为黑色
2.把叔叔也设为黑色
3.把祖父也就是父亲的父亲设为红色(爷爷)
4.把指针指向到祖父结点设为当前要操作的.
左旋:当前父结点是红色,叔叔是黑色的时候,且当前的结点是右子树。左旋以父结点作为左旋。
右旋:当前父结点是红色,叔叔是黑色的时候,且当前的结点是左子树。右旋
1.把父结点变为黑色
2.把祖父结点变为红色(爷爷)
3.以祖父结点旋转(爷爷)
删除规则
当删除一个节点时的变换规则:
自己是父亲的左儿子
自己为黑色、兄弟为红色、父节点为黑色
(1)将兄弟变成黑色,父节点变成红色;这时,以父节点为起点的左子树黑色高度降低
(2)对父节点进行左旋,以恢复左子树黑色高度;同时,兄弟的左孩子成为新的兄弟
此时,自己和兄弟都是黑色,父节点为黑色或红色;兄弟的两个儿子,都是黑色
(1)将兄弟变成为红色,x指向父节点,继续进行调整
此时,自己和兄弟均为黑色,父节点为红色或黑色;右侄子为黑色、左侄子为红色;
(1)将左侄子变成黑色,兄弟变为红色;这时,以兄弟为起点的右子树黑色高度降低
(2)将兄弟节点右旋,以恢复右子树的黑色高度;这时,左侄子将成为新的右兄弟
此时,自己和兄弟都是黑色,父节点为红色或黑色;右侄子为红色,左侄子为黑色或红色
(1)兄弟颜色改成与父节点一致,右侄子和父节点都变成黑色
(2)为了保证父节点变为黑色后,不影响所有路径的黑色高度,需要将父节点左旋(兄弟节点上提)
(3)x指向根节点,结束循环
自己是父亲的右儿子
此时,兄弟是红色节点,父节点必为黑色;若兄弟有左右儿子,左右儿子必为黑色
(1)将兄弟变成黑色节点,父节点变成红色;这时,以父节点为起点的右子树黑色高度降低
(2)将父节点右旋,以恢复右子树的黑色高度;这时,兄弟的右孩子成为新的兄弟
此时,自己和兄弟是黑色,父节点可以为红色或黑色
(1)将兄弟变成红色,x指向父节点,继续对父节点进行调整
此时,自己和兄弟均为黑色,父节点为黑色或红色;左侄子为黑色,右侄子为红色
(1)将右侄子变成黑色,兄弟变成红色;这是,以兄弟为起点的左子树黑色高度降低
(2)将兄弟左旋,以恢复左子树的黑色高度;这时,右侄子成为新的兄弟
此时,自己和兄弟均为黑色,父节点为红色或黑色;左侄子为红色,右侄子为红色或黑色
(1)将兄弟变成与父节点一样的颜色,左侄子和父节点变成黑色
(2)为了保证父节点变成黑色,不会影响所有路径的黑色高度,需要将父节点右旋(兄弟上提)
(3)x指向根节点,退出循环
RBTree.h:
#pragma once
#include<iostream>
#include<string>
#include<vector>
using namespace std;
#define RED false
#define BLACK true
struct RBNode {
int value;
RBNode* left;
RBNode* right;
RBNode* parent;
bool color; //默认是红色(false)
RBNode(int value) {
this->value = value;
this->left = nullptr;
this->right = nullptr;
this->parent = nullptr;
this->color = RED;
}
};
class RBTree
{
RBNode *root = nullptr;
public:
void insert(int val);//插入节点
void setColor(RBNode * node, bool color);//修改节点颜色
bool getColor(RBNode * node);//获取节点颜色空的为黑色
void rightXuan(RBNode * pivot);//右旋
void leftXuan(RBNode * pivot);//左旋
void insertAdjust(RBNode*x);//调整插入后的颜色变换和旋转
void printNode(RBNode*cur);//输出节点
void deleteNode(int value);//删除节点
void adjustDelete(RBNode*x);//删除前调整颜色变换和旋转
RBNode*getRoot();//获取根节点
RBNode*findNode(int value);//返回值为value的节点
RBNode * returnLeft(RBNode * parent);//返回parent节点的左孩子节点
RBNode * returnRight(RBNode * parent);//返回parent节点的右孩子节点
RBNode * returnParent(RBNode * child);//返回child节点的父亲节点
};
RBTree.cpp
#include "RBTree.h"
//插入节点
void RBTree::insert(int value)
{
RBNode* newNode = new RBNode(value);
if (root == nullptr) {
//根据红黑树的定义,根节点必须为黑色
newNode->color = BLACK;
root = newNode;
return;
}
//根据数值大小寻找位置
RBNode* cur = root;
RBNode* p = cur;
while (cur != nullptr) {
p = cur;
if (cur->value > value) {
//小于去左子树
cur = cur->left;
}
else if (cur->value == value) {
cout << value << "不能插入相同元素" << endl;
return;
}
else {
//大于去右子树
cur = cur->right;
}
}
//插入节点
if (p->value > value) {
p->left = newNode;
}
else {
p->right = newNode;
}
newNode->parent = p;
//插入后调整平衡
insertAdjust(newNode);
}
//插入调整
void RBTree::insertAdjust(RBNode*x)
{
/*当前结点的父亲是红色,且它的祖父结点的另一个子结点也就是uncle节点也是红色就需要变色。
1.把父节点设为黑色
2.把叔叔也设为黑色
3.把祖父也就是父亲的父亲设为红色(爷爷)
4.把指针指向到祖父结点设为当前要操作的.
左旋:当前父结点是红色,叔叔是黑色的时候,且当前的结点是右子树。左旋以父结点作为左旋。
右旋:当前父结点是红色,叔叔是黑色的时候,且当前的结点是左子树。右旋
5.把父结点变为黑色
6.把祖父结点变为红色(爷爷)
7.以祖父结点旋转(爷爷)*/
while (returnParent(x) != nullptr && getColor(returnParent(x)) == RED) {
if (returnLeft(returnParent(x)) == x) {//判断当前节点是左子树
RBNode* uncle = returnRight(returnParent(returnParent(x)));
if (getColor(uncle) == RED) {//判断叔叔
setColor(returnParent(x), BLACK);//1.
setColor(returnParent(returnParent(x)), RED);//3.
setColor(uncle, BLACK);//2.
x = returnParent(returnParent(x));//4.
}
else {//满足右旋条件
rightXuan(returnParent(returnParent(x)));//7.
setColor(returnParent(x), BLACK);//6.
setColor(returnRight(returnParent(x)), RED);//5.
//退出循环
x = root;
}
}
else {
//满足左旋条件
RBNode* uncle = returnLeft(returnParent(returnParent(x)));
if (getColor(uncle) == RED) {//判断是变色还是旋转
setColor(returnParent(x), BLACK);
setColor(returnParent(returnParent(x)), RED);
setColor(uncle, BLACK);
x = returnParent(returnParent(x));
}
else {//左旋
leftXuan(returnParent(returnParent(x)));
setColor(returnParent(x), BLACK);
setColor(returnLeft(returnParent(x)), RED);
x = root;
}
}
}
//根节点必须是黑色的
setColor(root, BLACK);
}
//先序遍历
void RBTree::printNode(RBNode * cur)
{
if (cur == nullptr) {
return;
}
cout << cur->value << " " << (cur->color == RED ? "red" : "black") << endl;
printNode(cur->left);
printNode(cur->right);
}
//删除
void RBTree::deleteNode(int value)
{
RBNode* node = findNode(value);
if (node == nullptr) {
cout << "红黑树中不存在" << value << ",删除失败。" << endl;
return;
}
//node为要删除的节点
if (node->left != nullptr && node->right != nullptr) {
//node节点的右子树的左节点
RBNode* s = node->right;
while (s != nullptr && s->left != nullptr) {
s = s->left;
}
node->value = s->value;
node = s;
}
//node为要删除的节点,replacement为代替node节点的节点
RBNode* replacement = node->left == nullptr ? node->right : node->left;
//删除的node节点是叶子节点
if (replacement == nullptr) {
//删除的是根节点,直接删除
if (node->parent == nullptr) {
root = nullptr;
}
else {
//删除的node节点是黑色的,先调整
if (getColor(node) == BLACK) {
adjustDelete(node);
}
//再删除
if (returnLeft(returnParent(node)) == node) {
node->parent->left = nullptr;
}
else {
node->parent->right = nullptr;
}
node->parent = nullptr;
}
}
else {
//node存在替代节点replacement,node节点一定是黑色节点,replacement节点一定是红色节点
replacement->color = BLACK;
replacement->parent = node->parent;
//删除的是根节点
if (node->parent == nullptr) {
root = replacement;
}
else if (node->parent->left == node) {
//删除的是父节点的左孩子
node->parent->left = replacement;
}
else {
//删除的是父节点的有孩子
node->parent->right = replacement;
}
//删除node节点对其他节点的引用关系,使其变成垃圾被回收掉
node->parent = node->left = node->right = nullptr;
}
}
//删除调整
void RBTree::adjustDelete(RBNode * x)
{
//x一定不是根节点且x节点一定是黑色的叶子节点
while (returnParent(x) != nullptr && getColor(x) == BLACK) {
//删除的x节点是父节点的左孩子
if (returnLeft(returnParent(x)) == x) {//自己是左儿子
RBNode* brother = returnRight(returnParent(x));
if (getColor(brother) == RED) {//1.
leftXuan(returnParent(x));
setColor(brother, BLACK);
setColor(returnParent(x), RED);
brother = returnRight(returnParent(x));
}
if (getColor(returnLeft(brother)) == BLACK && getColor(returnRight(brother)) == BLACK) {
setColor(brother, RED);
x = returnParent(x);
}
else {
if (getColor(returnRight(brother)) == BLACK) {
rightXuan(brother);
setColor(returnParent(brother), BLACK);
setColor(brother, RED);
brother = returnParent(brother);
}
leftXuan(returnParent(x));
setColor(brother, getColor(returnParent(x)));
setColor(returnParent(x), BLACK);
setColor(returnRight(brother), BLACK);
x = root;
}
}
else {
RBNode* brother = returnLeft(returnParent(x));
if (getColor(brother) == RED) {
rightXuan(returnParent(x));
setColor(brother, BLACK);
setColor(returnParent(x), RED);
brother = returnLeft(returnParent(x));
}
if (getColor(returnLeft(brother)) == BLACK && getColor(returnRight(brother)) == BLACK) {
setColor(brother, RED);
x = returnParent(x);
}
else {
if (getColor(returnLeft(brother)) == BLACK) {
leftXuan(brother);
setColor(brother, RED);
setColor(returnParent(brother), BLACK);
brother = returnParent(brother);
}
rightXuan(returnParent(x));
setColor(brother, getColor(returnParent(x)));
setColor(returnParent(x), BLACK);
setColor(returnLeft(brother), BLACK);
x = root;
}
}
}
setColor(x, BLACK);
}
//返回根节点
RBNode * RBTree::getRoot()
{
return root;
}
//寻找value值的节点
RBNode * RBTree::findNode(int value)
{
RBNode* cur = root;
while (cur != nullptr) {
if (cur->value > value) {
cur = cur->left;
}
else if (cur->value == value) {
return cur;
}
else {
cur = cur->right;
}
}
return nullptr;
}
//返回parent节点的左孩子节点
RBNode*RBTree::returnLeft(RBNode*parent) {
return parent == nullptr ? nullptr : parent->left;
}
//返回parent节点的右孩子节点
RBNode*RBTree::returnRight(RBNode*parent) {
return parent == nullptr ? nullptr : parent->right;
}
//返回child节点的父亲节点
RBNode* RBTree::returnParent(RBNode*child) {
return child == nullptr ? nullptr : child->parent;
}
//设置颜色
void RBTree::RBTree::setColor(RBNode*node, bool color) {
if (node == nullptr) return;
node->color = color;
}
//获取node节点的颜色
//如果node==nullptr,就返回黑色,否则返回node->color
bool RBTree::getColor(RBNode*node) {
return node == nullptr ? BLACK : node->color;
}
//右旋
void RBTree::rightXuan(RBNode*Node) {
RBNode* left = Node->left;
Node->left = left->right;
if (left->right != nullptr) {
left->right->parent = Node;
}
if (Node->parent == nullptr) {
//根节点为支点
root = left;
}
else if (Node->parent->left == Node) {
Node->parent->left = left;
}
else {
Node->parent->right = left;
}
left->parent = Node->parent;
left->right = Node;
Node->parent = left;
}
//左旋
void RBTree::leftXuan(RBNode * Node)
{
RBNode* right = Node->right;
Node->right = right->left;
if (right->left != nullptr) {
right->left->parent = Node;
}
if (Node->parent == nullptr) {
//根节点为支点
root = right;
}
else if (Node->parent->left == Node) {
Node->parent->left = right;
}
else {
Node->parent->right = right;
}
right->parent = Node->parent;
right->left = Node;
Node->parent = right;
}
main.cpp:
#include"RBTree.h"
int main()
{
vector<int>arr= { 13,8,17,12,11,15,25,6,22,27 };
RBTree Tree ;
for (int i = 0; i < arr.size(); i++) {
Tree.insert(arr[i]);
}
Tree.deleteNode(11);
Tree.deleteNode(12);
Tree.printNode(Tree.getRoot());
return 0;
}