红黑树是一棵特殊的二叉搜索树,它在每个结点上增加了一个存储位来表示结点的颜色,可以是Red或Black。通过对任何一条从根到叶子的简单路径上各个结点的颜色进行约束,红黑树确保没有一条路径会比其他路径长出2倍,因而是近似于平衡的。
一棵红黑树是满足下面红黑性质的二叉搜索树:
- 每个结点或是红色的,或是黑色的
- 根节点是黑色的
- 每个叶节点(NIL)是黑色的
- 如果一个结点是红色的,则它的两个子结点都是黑色的
- 对每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点
RedBlackTree.h
#pragma once
#include <iostream>
enum class Color : int
{
Red = 0,
Black = 1,
};
std::ostream& operator<<(std::ostream& os, const Color& color);
struct RedBlackTreeNode
{
RedBlackTreeNode(int key, Color color) :Parent(nullptr), Left(nullptr), Right(nullptr), Key(key), Color(color){ }
RedBlackTreeNode* Parent;
RedBlackTreeNode* Left;
RedBlackTreeNode* Right;
int Key;
Color Color;
void Print();
};
class RedBlackTree
{
public:
RedBlackTree();
~RedBlackTree();
void Report();
void InorderTreeWalk(RedBlackTreeNode* x);
void PreorderTreeWalk(RedBlackTreeNode* x);
void PostorderTreeWalk(RedBlackTreeNode* x);
RedBlackTreeNode* Minimum(RedBlackTreeNode* x);
RedBlackTreeNode* Maximum(RedBlackTreeNode* x);
void Insert(RedBlackTreeNode* z);
void Delete(RedBlackTreeNode* z);
private:
void LeftRotate(RedBlackTreeNode* x);
void RightRotate(RedBlackTreeNode* y);
void InsertFixUp(RedBlackTreeNode* z);
void DeleteFixUp(RedBlackTreeNode* z);
void Transplant(RedBlackTreeNode* u, RedBlackTreeNode* v);
void Release(RedBlackTreeNode* x);
public:
RedBlackTreeNode* Root;
RedBlackTreeNode* Nil;
};
void TestRedBlackTree();
RedBlackTree.cpp
#include "RedBlackTree.h"
#include <iostream>
#include <vector>
using namespace std;
ostream& operator<<(ostream& os, const Color& color)
{
if (color == Color::Red)
{
os << "Red";
}
else
{
os << "Black";
}
return os;
}
void RedBlackTreeNode::Print()
{
cout << "(" << Key << ": " << Color << ") ";
}
RedBlackTree::RedBlackTree()
{
Nil = new RedBlackTreeNode(0, Color::Black);
Root = Nil;
}
RedBlackTree::~RedBlackTree()
{
if (Root != nullptr)
{
Release(Root);
}
Root = nullptr;
if (Nil != nullptr)
{
delete Nil;
}
Nil = nullptr;
}
void RedBlackTree::Report()
{
cout << "PreorderTreeWalk:\t";
PreorderTreeWalk(Root);
cout << endl << "InorderTreeWalk:\t";
InorderTreeWalk(Root);
cout << endl << "PostorderTreeWalk:\t";
PostorderTreeWalk(Root);
cout << endl;
}
void RedBlackTree::InorderTreeWalk(RedBlackTreeNode* x)
{
if (x != Nil)
{
InorderTreeWalk(x->Left);
x->Print();
InorderTreeWalk(x->Right);
}
}
void RedBlackTree::PreorderTreeWalk(RedBlackTreeNode* x)
{
if (x != Nil)
{
x->Print();
PreorderTreeWalk(x->Left);
PreorderTreeWalk(x->Right);
}
}
void RedBlackTree::PostorderTreeWalk(RedBlackTreeNode* x)
{
if (x != Nil)
{
PostorderTreeWalk(x->Left);
PostorderTreeWalk(x->Right);
x->Print();
}
}
RedBlackTreeNode* RedBlackTree::Minimum(RedBlackTreeNode* x)
{
while (x->Left != nullptr)
{
x = x->Left;
}
return x;
}
RedBlackTreeNode* RedBlackTree::Maximum(RedBlackTreeNode* x)
{
while (x->Right != nullptr)
{
x = x->Right;
}
return x;
}
void RedBlackTree::Insert(RedBlackTreeNode* z)
{
auto x = Root;
RedBlackTreeNode* y = Nil;
while (x != Nil)
{
y = x;
if (z->Key < x->Key)
{
x = x->Left;
}
else
{
x = x->Right;
}
}
z->Parent = y;
if (y == Nil)
{
Root = z;
}
else if (z->Key < y->Key)
{
y->Left = z;
}
else
{
y->Right = z;
}
z->Left = Nil;
z->Right = Nil;
z->Color = Color::Red;
InsertFixUp(z);
}
void RedBlackTree::Delete(RedBlackTreeNode* z)
{
RedBlackTreeNode* x = nullptr;
auto y = z;
auto y_original_color = 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);
}
else
{
y = Minimum(z->Right);
y_original_color = y->Color;
x = y->Right;
if (y->Parent != z)
{
Transplant(y, y->Right);
y->Right = z->Right;
y->Right->Parent = y;
}
Transplant(z, y);
y->Left = z->Left;
y->Left->Parent = y;
y->Color = z->Color;
}
if (y_original_color == Color::Black)
{
DeleteFixUp(x);
}
}
void RedBlackTree::LeftRotate(RedBlackTreeNode* x)
{
auto y = x->Right;
x->Right = y->Left;
if (y->Left != Nil)
{
y->Left->Parent = x;
}
y->Parent = x->Parent;
if (x->Parent == Nil)
{
Root = y;
}
else if(x == x->Parent->Left)
{
x->Parent->Left = y;
}
else
{
x->Parent->Right = y;
}
y->Left = x;
x->Parent = y;
}
void RedBlackTree::RightRotate(RedBlackTreeNode* y)
{
auto x = y->Left;
y->Left = x->Right;
if (x->Right != Nil)
{
x->Right->Parent = y;
}
x->Parent = y->Parent;
if (y->Parent == Nil)
{
Root = x;
}
else if (y == y->Parent->Left)
{
y->Parent->Left = x;
}
else
{
y->Parent->Right = x;
}
x->Right = y;
y->Parent = x;
}
void RedBlackTree::InsertFixUp(RedBlackTreeNode* z)
{
while (z->Parent->Color == Color::Red)
{
if (z->Parent == z->Parent->Parent->Left)
{
auto y = z->Parent->Parent->Right;
if (y->Color == Color::Red)
{
z->Parent->Color = Color::Black;
y->Color = Color::Black;
z->Parent->Parent->Color = Color::Red;
z = z->Parent->Parent;
}
else
{
if (z == z->Parent->Right)
{
z = z->Parent;
LeftRotate(z);
}
z->Parent->Color = Color::Black;
z->Parent->Parent->Color = Color::Red;
RightRotate(z->Parent->Parent);
}
}
else
{
auto y = z->Parent->Parent->Left;
if (y->Color == Color::Red)
{
z->Parent->Color = Color::Black;
y->Color = Color::Black;
z->Parent->Parent->Color = Color::Red;
z = z->Parent->Parent;
}
else
{
if (z == z->Parent->Left)
{
z = z->Parent;
RightRotate(z);
}
z->Parent->Color = Color::Black;
z->Parent->Parent->Color = Color::Red;
LeftRotate(z->Parent->Parent);
}
}
}
Root->Color = Color::Black;
}
void RedBlackTree::DeleteFixUp(RedBlackTreeNode* x)
{
while (x != Root && x->Color == Color::Black)
{
if (x == x->Parent->Left)
{
auto w = x->Parent->Right;
if (w->Color == Color::Red) //case 1 => case 2、3、4
{
w->Color = Color::Black;
x->Parent->Color = Color::Red;
LeftRotate(x->Parent);
}
else // w->Color == Color::Black
{
if (w->Left->Color == Color::Black && w->Right->Color == Color::Black) //case 2
{
w->Color = Color::Red;
x = x->Parent;
}
else if (w->Right->Color == Color::Black) //case 3
{
w->Left->Color = Color::Black;
w->Color = Color::Red;
RightRotate(w);
}
else //w->Right->Color == Color::Red //case 4
{
w->Color = x->Parent->Color;
x->Parent->Color = Color::Black;
w->Right->Color = Color::Black;
LeftRotate(x->Parent);
x = Root;
}
}
}
else
{
auto w = x->Parent->Left;
if (w->Color == Color::Red)
{
w->Color = Color::Black;
x->Parent->Color = Color::Red;
RightRotate(x->Parent);
}
else // w->Color == Color::Black
{
if (w->Left->Color == Color::Black && w->Right->Color == Color::Black)
{
w->Color = Color::Red;
x = x->Parent;
}
else if (w->Left->Color == Color::Black)
{
w->Right->Color = Color::Black;
w->Color = Color::Red;
LeftRotate(w);
}
else // w->Left->Color == Color::Red
{
w->Color = x->Parent->Color;
x->Parent->Color = Color::Black;
w->Left->Color = Color::Black;
RightRotate(x->Parent);
x = Root;
}
}
}
}
x->Color = Color::Black;
}
void RedBlackTree::Transplant(RedBlackTreeNode* u, RedBlackTreeNode* 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;
}
void RedBlackTree::Release(RedBlackTreeNode* x)
{
if (x != Nil)
{
Release(x->Left);
Release(x->Right);
delete x;
}
}
void TestRedBlackTree()
{
vector<RedBlackTreeNode*> nodes;
for (auto i = 0; i < 15; i++)
{
nodes.push_back(new RedBlackTreeNode(i, Color::Red));
}
RedBlackTree* tree = new RedBlackTree();
for (auto node : nodes)
{
tree->Insert(node);
tree->Report();
}
for (auto node : nodes)
{
tree->Delete(node);
tree->Report();
}
}
输出:
PreorderTreeWalk: (0: Black)
InorderTreeWalk: (0: Black)
PostorderTreeWalk: (0: Black)
PreorderTreeWalk: (0: Black) (1: Red)
InorderTreeWalk: (0: Black) (1: Red)
PostorderTreeWalk: (1: Red) (0: Black)
PreorderTreeWalk: (1: Black) (0: Red) (2: Red)
InorderTreeWalk: (0: Red) (1: Black) (2: Red)
PostorderTreeWalk: (0: Red) (2: Red) (1: Black)
PreorderTreeWalk: (1: Black) (0: Black) (2: Black) (3: Red)
InorderTreeWalk: (0: Black) (1: Black) (2: Black) (3: Red)
PostorderTreeWalk: (0: Black) (3: Red) (2: Black) (1: Black)
PreorderTreeWalk: (1: Black) (0: Black) (3: Black) (2: Red) (4: Red)
InorderTreeWalk: (0: Black) (1: Black) (2: Red) (3: Black) (4: Red)
PostorderTreeWalk: (0: Black) (2: Red) (4: Red) (3: Black) (1: Black)
PreorderTreeWalk: (1: Black) (0: Black) (3: Red) (2: Black) (4: Black) (5: Red)
InorderTreeWalk: (0: Black) (1: Black) (2: Black) (3: Red) (4: Black) (5: Red)
PostorderTreeWalk: (0: Black) (2: Black) (5: Red) (4: Black) (3: Red) (1: Black)
PreorderTreeWalk: (1: Black) (0: Black) (3: Red) (2: Black) (5: Black) (4: Red) (6: Red)
InorderTreeWalk: (0: Black) (1: Black) (2: Black) (3: Red) (4: Red) (5: Black) (6: Red)
PostorderTreeWalk: (0: Black) (2: Black) (4: Red) (6: Red) (5: Black) (3: Red) (1: Black)
PreorderTreeWalk: (3: Black) (1: Red) (0: Black) (2: Black) (5: Red) (4: Black) (6: Black) (7: Red)
InorderTreeWalk: (0: Black) (1: Red) (2: Black) (3: Black) (4: Black) (5: Red) (6: Black) (7: Red)
PostorderTreeWalk: (0: Black) (2: Black) (1: Red) (4: Black) (7: Red) (6: Black) (5: Red) (3: Black)
PreorderTreeWalk: (3: Black) (1: Red) (0: Black) (2: Black) (5: Red) (4: Black) (7: Black) (6: Red) (8: Red)
InorderTreeWalk: (0: Black) (1: Red) (2: Black) (3: Black) (4: Black) (5: Red) (6: Red) (7: Black) (8: Red)
PostorderTreeWalk: (0: Black) (2: Black) (1: Red) (4: Black) (6: Red) (8: Red) (7: Black) (5: Red) (3: Black)
PreorderTreeWalk: (3: Black) (1: Black) (0: Black) (2: Black) (5: Black) (4: Black) (7: Red) (6: Black) (8: Black) (9: Red)
InorderTreeWalk: (0: Black) (1: Black) (2: Black) (3: Black) (4: Black) (5: Black) (6: Black) (7: Red) (8: Black) (9: Red)
PostorderTreeWalk: (0: Black) (2: Black) (1: Black) (4: Black) (6: Black) (9: Red) (8: Black) (7: Red) (5: Black) (3: Black)
PreorderTreeWalk: (3: Black) (1: Black) (0: Black) (2: Black) (5: Black) (4: Black) (7: Red) (6: Black) (9: Black) (8: Red) (10: Red)
InorderTreeWalk: (0: Black) (1: Black) (2: Black) (3: Black) (4: Black) (5: Black) (6: Black) (7: Red) (8: Red) (9: Black) (10: Red)
PostorderTreeWalk: (0: Black) (2: Black) (1: Black) (4: Black) (6: Black) (8: Red) (10: Red) (9: Black) (7: Red) (5: Black) (3: Black)
PreorderTreeWalk: (3: Black) (1: Black) (0: Black) (2: Black) (7: Black) (5: Red) (4: Black) (6: Black) (9: Red) (8: Black) (10: Black) (11: Red)
InorderTreeWalk: (0: Black) (1: Black) (2: Black) (3: Black) (4: Black) (5: Red) (6: Black) (7: Black) (8: Black) (9: Red) (10: Black) (11: Red)
PostorderTreeWalk: (0: Black) (2: Black) (1: Black) (4: Black) (6: Black) (5: Red) (8: Black) (11: Red) (10: Black) (9: Red) (7: Black) (3: Black)
PreorderTreeWalk: (3: Black) (1: Black) (0: Black) (2: Black) (7: Black) (5: Red) (4: Black) (6: Black) (9: Red) (8: Black) (11: Black) (10: Red) (12: Red)
InorderTreeWalk: (0: Black) (1: Black) (2: Black) (3: Black) (4: Black) (5: Red) (6: Black) (7: Black) (8: Black) (9: Red) (10: Red) (11: Black) (12: Red)
PostorderTreeWalk: (0: Black) (2: Black) (1: Black) (4: Black) (6: Black) (5: Red) (8: Black) (10: Red) (12: Red) (11: Black) (9: Red) (7: Black) (3: Black)
PreorderTreeWalk: (3: Black) (1: Black) (0: Black) (2: Black) (7: Red) (5: Black) (4: Black) (6: Black) (9: Black) (8: Black) (11: Red) (10: Black) (12: Black) (13: Red)
InorderTreeWalk: (0: Black) (1: Black) (2: Black) (3: Black) (4: Black) (5: Black) (6: Black) (7: Red) (8: Black) (9: Black) (10: Black) (11: Red) (12: Black) (13: Red)
PostorderTreeWalk: (0: Black) (2: Black) (1: Black) (4: Black) (6: Black) (5: Black) (8: Black) (10: Black) (13: Red) (12: Black) (11: Red) (9: Black) (7: Red) (3: Black)
PreorderTreeWalk: (3: Black) (1: Black) (0: Black) (2: Black) (7: Red) (5: Black) (4: Black) (6: Black) (9: Black) (8: Black) (11: Red) (10: Black) (13: Black) (12: Red) (14: Red)
InorderTreeWalk: (0: Black) (1: Black) (2: Black) (3: Black) (4: Black) (5: Black) (6: Black) (7: Red) (8: Black) (9: Black) (10: Black) (11: Red) (12: Red) (13: Black) (14: Red)
PostorderTreeWalk: (0: Black) (2: Black) (1: Black) (4: Black) (6: Black) (5: Black) (8: Black) (10: Black) (12: Red) (14: Red) (13: Black) (11: Red) (9: Black) (7: Red) (3: Black)
PreorderTreeWalk: (7: Black) (3: Black) (1: Black) (2: Red) (5: Red) (4: Black) (6: Black) (9: Black) (8: Black) (11: Red) (10: Black) (13: Black) (12: Red) (14: Red)
InorderTreeWalk: (1: Black) (2: Red) (3: Black) (4: Black) (5: Red) (6: Black) (7: Black) (8: Black) (9: Black) (10: Black) (11: Red) (12: Red) (13: Black) (14: Red)
PostorderTreeWalk: (2: Red) (1: Black) (4: Black) (6: Black) (5: Red) (3: Black) (8: Black) (10: Black) (12: Red) (14: Red) (13: Black) (11: Red) (9: Black) (7: Black)
PreorderTreeWalk: (7: Black) (3: Black) (2: Black) (5: Red) (4: Black) (6: Black) (9: Black) (8: Black) (11: Red) (10: Black) (13: Black) (12: Red) (14: Red)
InorderTreeWalk: (2: Black) (3: Black) (4: Black) (5: Red) (6: Black) (7: Black) (8: Black) (9: Black) (10: Black) (11: Red) (12: Red) (13: Black) (14: Red)
PostorderTreeWalk: (2: Black) (4: Black) (6: Black) (5: Red) (3: Black) (8: Black) (10: Black) (12: Red) (14: Red) (13: Black) (11: Red) (9: Black) (7: Black)
PreorderTreeWalk: (7: Black) (5: Black) (3: Black) (4: Red) (6: Black) (9: Black) (8: Black) (11: Red) (10: Black) (13: Black) (12: Red) (14: Red)
InorderTreeWalk: (3: Black) (4: Red) (5: Black) (6: Black) (7: Black) (8: Black) (9: Black) (10: Black) (11: Red) (12: Red) (13: Black) (14: Red)
PostorderTreeWalk: (4: Red) (3: Black) (6: Black) (5: Black) (8: Black) (10: Black) (12: Red) (14: Red) (13: Black) (11: Red) (9: Black) (7: Black)
PreorderTreeWalk: (7: Black) (5: Black) (4: Black) (6: Black) (9: Black) (8: Black) (11: Red) (10: Black) (13: Black) (12: Red) (14: Red)
InorderTreeWalk: (4: Black) (5: Black) (6: Black) (7: Black) (8: Black) (9: Black) (10: Black) (11: Red) (12: Red) (13: Black) (14: Red)
PostorderTreeWalk: (4: Black) (6: Black) (5: Black) (8: Black) (10: Black) (12: Red) (14: Red) (13: Black) (11: Red) (9: Black) (7: Black)
PreorderTreeWalk: (9: Black) (7: Black) (5: Black) (6: Red) (8: Black) (11: Black) (10: Black) (13: Black) (12: Red) (14: Red)
InorderTreeWalk: (5: Black) (6: Red) (7: Black) (8: Black) (9: Black) (10: Black) (11: Black) (12: Red) (13: Black) (14: Red)
PostorderTreeWalk: (6: Red) (5: Black) (8: Black) (7: Black) (10: Black) (12: Red) (14: Red) (13: Black) (11: Black) (9: Black)
PreorderTreeWalk: (9: Black) (7: Black) (6: Black) (8: Black) (11: Black) (10: Black) (13: Black) (12: Red) (14: Red)
InorderTreeWalk: (6: Black) (7: Black) (8: Black) (9: Black) (10: Black) (11: Black) (12: Red) (13: Black) (14: Red)
PostorderTreeWalk: (6: Black) (8: Black) (7: Black) (10: Black) (12: Red) (14: Red) (13: Black) (11: Black) (9: Black)
PreorderTreeWalk: (9: Black) (7: Black) (8: Red) (11: Red) (10: Black) (13: Black) (12: Red) (14: Red)
InorderTreeWalk: (7: Black) (8: Red) (9: Black) (10: Black) (11: Red) (12: Red) (13: Black) (14: Red)
PostorderTreeWalk: (8: Red) (7: Black) (10: Black) (12: Red) (14: Red) (13: Black) (11: Red) (9: Black)
PreorderTreeWalk: (9: Black) (8: Black) (11: Red) (10: Black) (13: Black) (12: Red) (14: Red)
InorderTreeWalk: (8: Black) (9: Black) (10: Black) (11: Red) (12: Red) (13: Black) (14: Red)
PostorderTreeWalk: (8: Black) (10: Black) (12: Red) (14: Red) (13: Black) (11: Red) (9: Black)
PreorderTreeWalk: (11: Black) (9: Black) (10: Red) (13: Black) (12: Red) (14: Red)
InorderTreeWalk: (9: Black) (10: Red) (11: Black) (12: Red) (13: Black) (14: Red)
PostorderTreeWalk: (10: Red) (9: Black) (12: Red) (14: Red) (13: Black) (11: Black)
PreorderTreeWalk: (11: Black) (10: Black) (13: Black) (12: Red) (14: Red)
InorderTreeWalk: (10: Black) (11: Black) (12: Red) (13: Black) (14: Red)
PostorderTreeWalk: (10: Black) (12: Red) (14: Red) (13: Black) (11: Black)
PreorderTreeWalk: (13: Black) (11: Black) (12: Red) (14: Black)
InorderTreeWalk: (11: Black) (12: Red) (13: Black) (14: Black)
PostorderTreeWalk: (12: Red) (11: Black) (14: Black) (13: Black)
PreorderTreeWalk: (13: Black) (12: Black) (14: Black)
InorderTreeWalk: (12: Black) (13: Black) (14: Black)
PostorderTreeWalk: (12: Black) (14: Black) (13: Black)
PreorderTreeWalk: (13: Black) (14: Red)
InorderTreeWalk: (13: Black) (14: Red)
PostorderTreeWalk: (14: Red) (13: Black)
PreorderTreeWalk: (14: Black)
InorderTreeWalk: (14: Black)
PostorderTreeWalk: (14: Black)
PreorderTreeWalk:
InorderTreeWalk:
PostorderTreeWalk:
E:\GitHub\IntroductionToAlgorithms\C++\build\Debug\IntroductionToAlgorithms.exe (进程 29540)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .