题记
最近甚是苦闷,因为没有组成队伍。于是为了排解无聊,决定手搓一棵红黑树。心想我连avl树都写完了,不如再搞红黑树。反正应该不难吧?(doge)但是写完我才后悔了,这东西真难写,为此我不得不参考许多了资料,尤其是B站的up主@木子喵neko 和@哈哈哈哈栋 的说明。
红黑树和一般的二叉搜索树一样,都需要实现增加节点、删除节点、查询节点三个函数。查询函数和一般二叉树的情形完全一致。插入部分的代码基本就是照搬@哈哈哈哈栋 而 删除的办法则是参考@木子喵neko的做法。具体原因是前者的代码能直接看懂并且改造,但是关于删除的部分讲得却不那么方便代码实现。
在弄清楚原理后,就要开始构建了。在构建之前,我们先准备一些辅助函数,比如左右旋转的函数,又比如安全检查节点颜色的函数(这个很重要,因为能防止外部节点作为空指针被访问),安全建立父子关系建立的函数。
同时,我们也要做好释放空间的操作,比如析构函数就改写成析构的样式。
然后,我就开开心心地开始了构建!
源码
//
// Created by Mirror on 24-11-29.
//
#ifndef BLACK_RED_TREE_HPP
#define BLACK_RED_TREE_HPP
#define RED 1
#define BLACK 0
#include <iostream>
typedef struct Black_Red_Tree_Node {
unsigned char color;
int data;
Black_Red_Tree_Node *left = nullptr;
Black_Red_Tree_Node *right = nullptr;
Black_Red_Tree_Node*parent=nullptr;
explicit Black_Red_Tree_Node(const int data):color(BLACK),data(data){}
void Right_handed_rotation(Black_Red_Tree_Node *root) {
//LL
if (root == nullptr || root->left == nullptr)return;
Black_Red_Tree_Node* new_root = root ->left;
Black_Red_Tree_Node* T2 = new_root->right;
root->left = T2;
if (T2 != nullptr) {
T2->parent = root;
}//更新某些的父节点指针需要检查
new_root->parent = root->parent;
if (root->parent != nullptr) {
if (root->parent->left == root) {
root->parent->left = new_root;
}else if (root->parent->right == root) {
root->parent->right = new_root;
}
}
root->parent = new_root;
new_root->right = root;
}
void Left_handed_rotation(Black_Red_Tree_Node *root) {
//RR
if (root == nullptr || root->right == nullptr)return;
Black_Red_Tree_Node* new_root = root ->right;
Black_Red_Tree_Node* T2 = new_root->left;
root->right = T2;
if (T2 != nullptr) {
T2->parent = root;
}//更新某些的父节点指针需要检查
//新根的父节点也要改
new_root->parent = root->parent;
if (root->parent != nullptr) {
if (root->parent->left == root) {
root->parent->left = new_root;
}else if (root->parent->right == root) {
root->parent->right = new_root;
}
}
root->parent = new_root;
new_root->left = root;
}
static bool insert(Black_Red_Tree_Node* root , const int element) {
Black_Red_Tree_Node* current = root;
Black_Red_Tree_Node* previous = root;
while (current != nullptr) {
previous = current;
if (current->data < element) {
current = current ->right;
continue;
}
if (current->data == element) {
return false;
}
if (current->data > element) {
current = current->left;
//continue;
}
}
if (previous != nullptr) {
Black_Red_Tree_Node* NewNode = new Black_Red_Tree_Node(element);
NewNode->parent = previous;
NewNode->color = RED;//所有插入的节点都是红色的
if (previous->data < element) {
previous->right = NewNode;
}else {
previous->left = NewNode;
}
return true;
}
return false;
}
static std::pair<bool,Black_Red_Tree_Node*>Delete_Red_Leaf_Node(Black_Red_Tree_Node* node) {
if (node == nullptr || node->color == BLACK || node->left != nullptr || node->right != nullptr)
return {false,nullptr};
Black_Red_Tree_Node *Parent = node->parent;
if (Parent->left == node) {
delete Parent->left;
Parent->left = nullptr;
}else {
delete Parent->right;
Parent->right = nullptr;
}
return {true,Parent};
}//安全删除红色叶子节点
std::pair<bool,Black_Red_Tree_Node*> insert(const int element) {
Black_Red_Tree_Node* current = this;
Black_Red_Tree_Node* previous = this;
while (current != nullptr) {
previous = current;
if (current->data < element) {
current = current ->right;
continue;
}
if (current->data == element) {
return {false, current};
}
if (current->data > element) {
current = current->left;
//continue;
}
}
Black_Red_Tree_Node* NewNode = new Black_Red_Tree_Node(element);
NewNode->parent = previous;
NewNode->color = RED;//所有插入的节点都是红色的
if (previous->data < element) {
previous->right = NewNode;
return {true,previous->right};
}else {
previous->left = NewNode;
}
return {true,previous->left};
}
std::pair<bool,Black_Red_Tree_Node*>find(const int key) {
Black_Red_Tree_Node* current = this;
Black_Red_Tree_Node* previous = this;
while (current != nullptr) {
previous = current;
if (current->data < key) {
current = current ->right;
continue;
}
if (current->data == key) {
break;
}
if (current->data > key) {
current = current->left;
//continue;
}
}
if (current == nullptr) {
return {false , previous};
}
return {true,current};
}
std::pair<bool,Black_Red_Tree_Node*>Lowest_Upper_Bound() {
if (right == nullptr)return {false,this};
Black_Red_Tree_Node* current = right;
while (current->left!= nullptr) {
current = current->left;
}
return {true , current};
}
std::pair<bool,Black_Red_Tree_Node*>Biggest_Lower_Bound() {
if (left == nullptr)return {false,this};
Black_Red_Tree_Node* current = left;
while ( current->right != nullptr) {
current = current->right;
}
return {true , current};
}
static bool isBlack(const Black_Red_Tree_Node* node) {
return node == nullptr || node->color == BLACK;
//实际上更安全的写法应该是
//return node == nullptr ? 1 : node->color == BLACK;
}//用于安全地检查节点是否为黑色(利用短路)
static bool isRed(const Black_Red_Tree_Node* node) {
return node != nullptr && node->color == RED;
//等价写法为
//return !isBlack(node);
}//用于安全地检查节点是否为红色(利用短路)
static bool set_Parent_Child_relationship(Black_Red_Tree_Node*Parent,Black_Red_Tree_Node*Child) {
if (Parent == nullptr || Child == nullptr || Parent->data == Child->data || Parent == Child)return false;
if (Parent->left != nullptr && Parent->data > Child->data)return false;
if (Parent->right != nullptr && Parent->data < Child->data)return false;
if (Parent->data > Child->data) {
Parent->left = Child;
Child->parent = Parent;
}else {
Parent->right = Child;
Child->parent = Parent;
}
return true;
}//安全地建立父子关系
static bool Delete_From_Root(Black_Red_Tree_Node* root) {
if (root != nullptr) {
root->parent = nullptr;
delete root;
return true;
}
return false;
}
~Black_Red_Tree_Node() {
if (left != nullptr) {
delete left;
left = nullptr;
}
if (right != nullptr) {
delete right;
right = nullptr;
}
if (parent != nullptr) {
if (parent->left == this) {
parent->left = nullptr;
}else if (parent->right ==this){
parent->right = nullptr;
}
parent = nullptr;
}
//递归析构二叉树
// std::cout << "~Black_Red_Tree_Node"<<std::endl;
}//注意:不能delete parent,否则会陷入死循环,因此直接解除双方的父子关系即可
} BRtree_node;
struct Black_Red_Tree{
BRtree_node* root;
explicit Black_Red_Tree():root(nullptr){}
explicit Black_Red_Tree(const int e) {
root = new BRtree_node(e);
}
std::pair<bool,BRtree_node*> insert(const int element) {
if (root != nullptr) {
Black_Red_Tree_Node* current = root->insert(element).second;
Black_Red_Tree_Node* location = current;
//获取当前插入节点的位置
while (Black_Red_Tree_Node::isRed(current->parent)) {
if (current->parent == current->parent->parent->left) {
//LXx
Black_Red_Tree_Node* uncle = current->parent->parent->right;
if (Black_Red_Tree_Node::isRed(uncle) ) {
//Lxr
current->parent->color = BLACK;
uncle->color = BLACK;
current->parent->parent->color = RED;
current = current->parent->parent;
}else /*if(Black_Red_Tree_Node::isBlack(uncle))*/{
//LRb
if (current == current->parent->right) {
//调整为LLb
current = current->parent;
current->Left_handed_rotation(current);
}
//LLb
current->parent->color = BLACK;
current->parent->parent->color = RED;
current->parent->parent->Right_handed_rotation(current->parent->parent);
}
}
else/*if (current->parent = current->parent->parent->right)*/ {
//RXx
Black_Red_Tree_Node* uncle = current->parent->parent->left;
if (Black_Red_Tree_Node::isRed(uncle) ) {
//Rxr
current->parent->color = BLACK;
uncle->color = BLACK;
current->parent->parent->color = RED;
current = current->parent->parent;
}else /*if(Black_Red_Tree_Node::isBlack(uncle))*/{
//RLb
if (current == current->parent->left) {
//调整为RRb
current = current->parent;
current->Right_handed_rotation(current);
}
//RRb
current->parent->color = BLACK;
current->parent->parent->color = RED;
current->parent->parent->Left_handed_rotation(current->parent->parent);
}
}
}
RenewRoot();
//因为左旋和右旋可能会改变根的位置,所以要维护根节点位置
root->color = BLACK;
//染色操作可能会导致根节点变色,于是要维护黑色
return {true,location};
}
root = new Black_Red_Tree_Node(element);
return {true,root};
}
std::pair<bool,BRtree_node*>find(const int key) {
if (root == nullptr) {
//std::cout << "[ root == nullptr ] Failed to search "<<key<<std::endl;
return {false,root};
}
std::pair<bool,BRtree_node*>res = root->find(key);
if (res.first) {
//std::cout <<"key : "<<key<< " has been found at "<<res.second<<std::endl;
}else {
//std::cout << "[ key isn't exist at the BR_Tree ] Failed to search"<<std::endl;
}
return res;
}
bool RenewRoot() {
if (root == nullptr)return false;
while (root->parent != nullptr) {
root = root->parent;
}
return true;
}
std::pair<bool,BRtree_node*> Delete(const int key) {
std::pair<bool,BRtree_node*> Find = find(key);
bool exist = Find.first;//用于防止重复删除节点
if (!exist)return {false,Find.second};
BRtree_node* target = Find.second;
//删除红色节点
if (Black_Red_Tree_Node::isRed(target)) {
BRtree_node* Left = target->left;
BRtree_node* Right = target->right;
if (Left == nullptr && Right == nullptr) {
return Black_Red_Tree_Node::Delete_Red_Leaf_Node(target);
}//直接删除红色叶子节点
if (Left != nullptr) {
Black_Red_Tree_Node*NewTarget = target->Biggest_Lower_Bound().second;
std::swap(target->data,NewTarget->data);
target = NewTarget;
//更新目标删除节点
if (Black_Red_Tree_Node::isRed(target)) {
Black_Red_Tree_Node*Parent = target->parent;
Black_Red_Tree_Node*LeftChild = target->left;
target->left = nullptr;
Parent->right = nullptr;
Black_Red_Tree_Node::set_Parent_Child_relationship(Parent,LeftChild);
delete target;
exist = false;
}else {
goto Delete_Black_Node;
//接替的节点为黑色,直接转换为删除黑色节点的情形,所以使用goto语句进入下文
}
}else /* if(Right != nullptr) */{
Black_Red_Tree_Node*NewTarget = target->Lowest_Upper_Bound().second;
std::swap(target->data,NewTarget->data);
target = NewTarget;
//更新目标删除节点
if (Black_Red_Tree_Node::isRed(target)) {
Black_Red_Tree_Node*Parent = target->parent;
Black_Red_Tree_Node*RightChild = target->right;
target->right = nullptr;
Parent->left = nullptr;
Black_Red_Tree_Node::set_Parent_Child_relationship(Parent,RightChild);
delete target;
exist = false;
}else {
goto Delete_Black_Node;
//接替的节点为黑色,直接转换为删除黑色节点的情形,所以使用goto语句进入下文
}
}
//所要删除的红色节点的 接替的前驱/后驱节点若为红色
//先交换数据,然后简单删除接替的红色节点
}else {
Delete_Black_Node:
BRtree_node* Left = target->left;
BRtree_node* Right = target->right;
//删除黑色节点的情况比较复杂
//1、我们先讨有论接替节点且节点为红色或者(黑色)的情形
if (Left != nullptr) {
Black_Red_Tree_Node*NewTarget = target->Biggest_Lower_Bound().second;
std::swap(target->data,NewTarget->data);
target = NewTarget;
//更新目标删除节点
if (Black_Red_Tree_Node::isRed(target)) {
Black_Red_Tree_Node*Parent = target->parent;
Black_Red_Tree_Node*LeftChild = target->left;
target->left = nullptr;
Parent->left = nullptr;
Black_Red_Tree_Node::set_Parent_Child_relationship(Parent,LeftChild);
delete target;
exist = false;
}else {
goto Delete_Black_Node;
//接替的节点为黑色,直接转换为删除黑色节点的情形,所以使用goto语句回到前文
}
}else if(Right != nullptr) {
Black_Red_Tree_Node*NewTarget = target->Lowest_Upper_Bound().second;
std::swap(target->data,NewTarget->data);
target = NewTarget;
//更新目标删除节点
if (Black_Red_Tree_Node::isRed(target)) {
Black_Red_Tree_Node*Parent = target->parent;
Black_Red_Tree_Node*RightChild = target->right;
target->right = nullptr;
Parent->left = nullptr;
Black_Red_Tree_Node::set_Parent_Child_relationship(Parent,RightChild);
delete target;
exist = false;
}else {
goto Delete_Black_Node;
//接替的节点为黑色,直接转换为删除黑色节点的情形,所以使用goto语句回到前文
}
}else {
__DELETE__BLACK_LEAF_NODE__:
//2、没有接替节点,目标删除节点为黑色叶子节点
//(1)根节点的情形
if (target->parent == nullptr) {
if (exist) {
exist = false;
delete target;
target = nullptr;
root = nullptr;
//为什么这里不直接delete root呢?
//是因为在递归调整的过程中root不是根节点了,即 target 不一定等于 root
//
}
return {true , nullptr};
}
//(2)兄弟节点为黑色的情形
if (target->parent->left == target && Black_Red_Tree_Node::isBlack(target->parent->right)) {
//(2.1)兄弟节点有红色子节点,拿来修复红黑树
Black_Red_Tree_Node*Parent = target->parent;
Black_Red_Tree_Node*Brother = Parent->right;
if (exist) {
exist = false;
delete target;
target = nullptr;
Parent->left = nullptr;
}
if (Black_Red_Tree_Node::isRed(Brother->right)) {
//RR
Brother->color = Parent->color;
Parent->Left_handed_rotation(Parent);
Brother->left->color = BLACK;
Brother->right->color = BLACK;
}else if (Black_Red_Tree_Node::isRed(Brother->left)) {
//RL
Black_Red_Tree_Node*FinalRoot = Brother->left;
FinalRoot->color = Parent->color;
Brother->Right_handed_rotation(Brother);
Parent->Left_handed_rotation(Parent);
FinalRoot->left->color = BLACK;
FinalRoot->right->color = BLACK;
}
//(2.2)兄弟节点没有红色子节点于是又要分情况讨论
//(2.2.1)父节点是红色的
else if (Black_Red_Tree_Node::isRed(Parent)) {
Parent->color = BLACK;
Brother->color = RED;
}
//(2.2.1)父节点是黑色的
else if (Black_Red_Tree_Node::isBlack(Parent)) {
Brother->color = RED;
target = Parent;
//递归回到上文去处理,同时假装target是一个外部节点
//这种幻想有利于处理
goto __DELETE__BLACK_LEAF_NODE__;
}
}else if (target->parent->right == target && Black_Red_Tree_Node::isBlack(target->parent->left)) {
Black_Red_Tree_Node*Parent = target->parent;
Black_Red_Tree_Node*Brother = Parent->left;
if (exist) {
exist = false;
delete target;
target = nullptr;
Parent->right = nullptr;
}
if (Black_Red_Tree_Node::isRed(Brother->left)) {
//LL
Brother->color = Parent->color;
Parent->Right_handed_rotation(Parent);
Brother->left->color = BLACK;
Brother->right->color = BLACK;
}else if (Black_Red_Tree_Node::isRed(Brother->right )) {
//LR
Black_Red_Tree_Node*FinalRoot = Brother->right;
FinalRoot->color = Parent->color;
Brother->Left_handed_rotation(Brother);
Parent->Right_handed_rotation(Parent);
FinalRoot->left->color = BLACK;
FinalRoot->right->color = BLACK;
}
//(2.2)兄弟节点没有红色子节点于是又要分情况讨论
//(2.2.1)父节点是红色的
else if (Black_Red_Tree_Node::isRed(Parent)) {
Parent->color = BLACK;
Brother->color = RED;
}
//(2.2.2)父亲节点是黑色的
else if (Black_Red_Tree_Node::isBlack(Parent)) {
Brother->color = RED;
target = Parent;
goto __DELETE__BLACK_LEAF_NODE__;
}
}
//(3)兄弟节点为红色的情形,通过染色和旋转变为兄弟节点为黑色的情况,即情况二
//旋转和染色这两部可以调换顺序
//但是要注意的是,这个过程结束后要进行递归,这里采用的是goto语句实现
else if (target->parent->left == target && Black_Red_Tree_Node::isRed(target->parent->right)) {
Black_Red_Tree_Node*Parent = target->parent;
Black_Red_Tree_Node*Brother = Parent->right;
//RR
Parent->Left_handed_rotation(Parent);
Parent->color = RED;
Brother->color = BLACK;
goto __DELETE__BLACK_LEAF_NODE__;
}else if (target->parent->right == target && Black_Red_Tree_Node::isRed(target->parent->left)) {
Black_Red_Tree_Node*Parent = target->parent;
Black_Red_Tree_Node*Brother = Parent->left;
//LL
Parent->Right_handed_rotation(Parent);
Parent->color = RED;
Brother->color = BLACK;
goto __DELETE__BLACK_LEAF_NODE__;
}
}
}
RenewRoot();
//更新根节点的原因是调整过程中可能会更改根节点的位置,所以要维护其位置
return {true,nullptr};
}
static void TreeDestroy(Black_Red_Tree *T) {
delete T;
T = nullptr;
}
static std::pair<bool,BRtree_node*>find(BRtree_node*root ,const int key) {
if (root == nullptr) {
std::cout << "[ root == nullptr ]Failed to search "<<key<<std::endl;
return {false,root};
}
std::pair<bool,BRtree_node*>res = root->find(key);
if (res.first) {
std::cout <<"key : "<<key<< " has been found at "<<res.second<<std::endl;
}else {
std::cout << "[ key isn't exist at the BR_Tree ]Failed to search"<<std::endl;
}
return res;
}
~Black_Red_Tree() {
delete root;
root = nullptr;
// std::cout<<"~Black_Red_Tree"<<std::endl;
}
};
typedef Black_Red_Tree* BRtree_Ptr;
typedef const Black_Red_Tree*const Const_BR_Ptr;
void preOrder(const BRtree_node* T);
void midOrder(const BRtree_node* T);
void aftOrder(const BRtree_node* T);
void preOrder(BRtree_Ptr T);
void midOrder(BRtree_Ptr T);
void aftOrder(BRtree_Ptr T);
#endif //BLACK_RED_TREE_HPP
后记
C++的STL库中的set和map都是用红黑树实现的,因此受到了很多人和组织的关注。但是事实上这种结构的代码非常不好写,主要是因为特殊情况繁多且上下文逻辑链巨长(这导致书写的效率不太高,当然不排除这是因为我自己的代码水平有限)。如果没有太高学习要求的话建议是直接用就行了。