C++数据结构 之 红黑树_Red Black Tree
源代码只包含头文件
注:需要C++11的支持
一、红黑树
之前有篇文章讲解了什么是二叉搜索树,而红 黑树是一颗二叉搜索树,它在每一个节点上增加了一个存储位来表示节点的颜色 (Red or Black)。
通过任何一条从根节点到子叶的简单路径上个点的颜色约束,红黑树确保没有一条路径会比其他路径长出2倍,因而是近似平衡。
一颗红黑树是满足下面红黑性质的二叉搜索树:
(1)每一个节点毛么事红色,要么是黑色。
(2)根节点是黑色。
(3)每一个叶节点(NIL)是黑色。
(4)如果一个节点是红色,则它的两个子节点都是黑色。
(5)对每个节点,从该节点到其所有后代叶结点的简单路径上,均包含相同数目的黑色节点。
支持的操作:
1、insert 插入元素
2、delete 删除元素
3、search 搜索元素
4、Inorder_Tree_Walk 中序遍历;Preorder_Tree_Walk 先序遍历;Postorder_Tree_Walk 后序遍历
5、Tree_Maximum、Tree_Minimum 基于键值(key)的最大最小值
5、Tree_Successor、Tree_Predecessor基于键值(key)的前驱后继
二、源代码:
(1)常规版本:
#ifndef RED_BLACK_TREE_H
#define RED_BLACK_TREE_H
#include <iostream>
#include <stack>
#include <memory>
#include <stdexcept>
using std::shared_ptr;
using std::cout;
using std::endl;
class RBT {
private:
enum Color { Red, Black };
struct Node {
Node() = default;
Node(const Color &c) : color(c) {}
Node(const long long &d, const Color &c, const shared_ptr<Node> &p, const shared_ptr<Node> &l, const shared_ptr<Node> &r) :
key(d), color(c), parent(p), left(l), right(r) {}
long long key;
Color color;
shared_ptr<Node> parent = nullptr;
shared_ptr<Node> left = nullptr;
shared_ptr<Node> right = nullptr;
};
shared_ptr<Node> NIL = std::make_shared<Node>(Black);
shared_ptr<Node> Root = NIL;
public:
RBT() = default;
~RBT() = default;
void Inorder_Tree_Walk(const shared_ptr<Node> &p) {
if (p != NIL) {
Inorder_Tree_Walk(p->left);
cout << p->key << " ";
if (p->color == Black)
cout << "Black " << endl;
else
cout << "Red " << endl;
Inorder_Tree_Walk(p->right);
}
}
void Inorder_Tree_Walk() {
auto p = Root;
if (p != NIL) {
Inorder_Tree_Walk(p->left);
cout << p->key << " ";
if (p->color == Black)
cout << "Black " << endl;
else
cout << "Red " << endl;
Inorder_Tree_Walk(p->right);
}
}
void Preorder_Tree_Walk(const shared_ptr<Node> &p) {
if (p != NIL) {
cout << p->key << " ";
if (p->color == Black)
cout << "Black " << endl;
else
cout << "Red " << endl;
Preorder_Tree_Walk(p->left);
Preorder_Tree_Walk(p->right);
}
}
void Preorder_Tree_Walk() {
auto p = Root;
if (p != NIL) {
cout << p->key << " ";
if (p->color == Black)
cout << "Black " << endl;
else
cout << "Red " << endl;
Preorder_Tree_Walk(p->left);
Preorder_Tree_Walk(p->right);
}
}
void Postorder_Tree_Walk(const shared_ptr<Node> &p) {
if (p != NIL) {
Postorder_Tree_Walk(p->left);
Postorder_Tree_Walk(p->right);
cout << p->key << " ";
if (p->color == Black)
cout << "Black " << endl;
else
cout << "Red " << endl;
}
}
void Postorder_Tree_Walk() {
auto p = Root;
if (p != NIL) {
Postorder_Tree_Walk(p->left);
Postorder_Tree_Walk(p->right);
cout << p->key << " ";
if (p->color == Black)
cout << "Black " << endl;
else
cout << "Red " << endl;
}
}
shared_ptr<Node> Tree_Successor(const long long &x) {
auto p = Search(x);
if (p->right != NIL) {
return Tree_Successor(p->right->key);
}
auto y = p->parent;
while (y != NIL && p == y->right) {
p = y;
y = y->parent;
}
return y;
}
shared_ptr<Node> Tree_Predecessor(const long long &x) {
auto p = Search(x);
if (p->left != NIL) {
return Tree_Predecessor(p->left->key);
}
auto y = p->parent;
while (y != NIL && p == y->left) {
p = y;
y = y->parent;
}
return y;
}
shared_ptr<Node> Tree_Maximum(const shared_ptr<Node> &Root) {
auto p = Root;
while (p->right != NIL) {
p = p->right;
}
return p;
}
shared_ptr<Node> Tree_Minimum(const shared_ptr<Node> &Root) {
auto p = Root;
while (p->left != NIL) {
p = p->left;
}
return p;
}
void Left_Rotate(shared_ptr<Node> Px) {
auto Py = Px->right;
Px->right = Py->left;
if (Py->left != NIL) {
Py->left->parent = Px;
}
Py->parent = Px->parent;
if (Px->parent == NIL) {
Root = Py;
}
else if (Px == Px->parent->left) {
Px->parent->left = Py;
}
else {
Px->parent->right = Py;
}
Py->left = Px;
Px->parent = Py;
}
void Right_Rotate(shared_ptr<Node> Py) {
auto Px = Py->left;
Py->left = Px->right;
if (Px->right != NIL) {
Px->right->parent = Py;
}
Px->parent = Py->parent;
if (Py->parent == NIL) {
Root = Px;
}
else if (Py == Py->parent->left) {
Py->parent->left = Px;
}
else {
Py->parent->right = Px;
}
Px->right = Py;
Py->parent = Px;
}
void Transplant(const shared_ptr<Node> &p1, const shared_ptr<Node> &P2) {
if (p1->parent == NIL) {
Root = P2;
}
else if (p1 == p1->parent->left) {
p1->parent->left = P2;
}
else {
p1->parent->right = P2;
}
P2->parent = p1->parent;
}
shared_ptr<Node> Search(const long long &x) {
auto p = Root;
while (p != NIL && x != p->key) {
if (x < p->key) {
p = p->left;
}
else {
p = p->right;
}
}
try {
if (p == NIL) {
throw std::runtime_error("The element was not found.");
}
}
catch (std::runtime_error err) {
cout << err.what() << endl;
}
return p;
}
void Insert(const long long &key) {
shared_ptr<Node> New = std::make_shared<Node>(key, Red, NIL, NIL, NIL);
auto Px = Root, Py = NIL;
while (Px != NIL) {
Py = Px;
if (key < Px->key) {
Px = Px->left;
}
else {
Px = Px->right;
}
}
New->parent = Py;
if (Py == NIL) {
Root = New;
}
else if (key < Py->key) {
Py->left = New;
}
else {
Py->right = New;
}
Rb_Insert_Fixup(New);
}
void Rb_Insert_Fixup(shared_ptr<Node> &p) {
while (p->parent->color == Red) {
if (p->parent == p->parent->parent->left) {
auto Py = p->parent->parent->right;
if (Py->color == Red) {
p->parent->color = Black;
Py->color = Black;
p->parent->parent->color = Red;
p = p->parent->parent;
}
else {
if (p == p->parent->right) {
p = p->parent;
Left_Rotate(p);
}
p->parent->color = Black;
p->parent->parent->color = Red;
Right_Rotate(p->parent->parent);
}
}
else {
auto Py = p->parent->parent->left;
if (Py->color == Red) {
p->parent->color = Black;
Py->color = Black;
p->parent->parent->color = Red;
p = p->parent->parent;
}
else {
if (p == p->parent->left) {
p = p->parent;
Right_Rotate(p);
}
p->parent->color = Black;
p->parent->parent->color = Red;
Left_Rotate(p->parent->parent);
}
}
}
Root->color = Black;
}
void Delete(const long long &key) {
auto p = Search(key);
auto Py = p;
shared_ptr<Node> Px;
Color y_original_color = Py->color;
if (p != NIL) {
if (p->left == NIL) {
Px = p->right;
Transplant(p, p->right);
}
else if (p->right == NIL) {
Px = p->left;
Transplant(p, p->left);
}
else {
Py = Tree_Minimum(p->right);
y_original_color = Py->color;
Px = Py->right;
if (Py->parent == p) {
Px->parent = Py;
}
else {
Transplant(Py, Py->right);
Py->right = p->right;
Py->right->parent = Py;
}
Transplant(p, Py);
Py->left = p->left;
Py->left->parent = Py;
Py->color = p->color;
}
if (y_original_color == Black) {
Rb_Delete_Fixup(Px);
}
}
}
void Rb_Delete_Fixup(shared_ptr<Node> &p) {
while (p != Root && p->color == Black) {
if (p == p->parent->left) {
auto w = p->parent->right;
if (w->color == Red) {
w->color = Black;
p->parent->color = Red;
Left_Rotate(p->parent);
w = p->parent->right;
}
if (w->left->color == Black && w->right->color == Black) {
w->color = Red;
p = p->parent;
}
else {
if (w->right->color == Black) {
w->left->color = Black;
w->color = Red;
Right_Rotate(w);
w = p->parent->right;
}
w->color = p->parent->color;
p->parent->color = Black;
w->right->color = Black;
Left_Rotate(p->parent);
p = Root;
}
}
else {
auto w = p->parent->left;
if (w->color == Red) {
w->color = Black;
p->parent->color = Red;
Right_Rotate(p->parent);
w = p->parent->left;
}
if (w->right->color == Black && w->left->color == Black) {
w->color = Red;
p = p->parent;
}
else {
if (w->left->color == Black) {
w->right->color = Black;
w->color = Red;
Left_Rotate(w);
w = p->parent->right;
}
w->color = p->parent->color;
p->parent->color = Black;
w->left->color = Black;
Right_Rotate(p->parent);
p = Root;
}
}
}
p->color = Black;
}
size_t Tree_Hight(const shared_ptr<Node> &p) {
if (p != NIL) {
size_t left = Tree_Hight(p->left);
size_t right = Tree_Hight(p->right);
if (left > right) {
return left + 1;
}
else {
return right + 1;
}
}
else {
return 0;
}
}
size_t Tree_Hight() {
return Tree_Hight(Root);
}
};
#endif // !RED_BLACK_TREE_H
(2)带有卫星数据的版本:
然而就是这微小差别,导致了此版本只能在 x86 环境下才能良好运行。不知为何(°o°;)…
也许是hash函数的问题…
不过此版本比常规版本构建的二叉树更平衡。
#ifndef RED_BLACK_TREE_X86_H
#define RED_BLACK_TREE_X86_H
#include <iostream>
#include <memory>
#include <utility>
#include <stdexcept>
#include <functional>
using std::shared_ptr;
using std::pair;
using std::cout;
using std::endl;
template<typename T>
class RBT {
private:
enum Color { Red, Black };
struct Node {
Node() = default;
Node(const Color &c) : color(c) {}
Node(const pair<size_t, T> &d, const Color &c, const shared_ptr<Node> &p, const shared_ptr<Node> &l, const shared_ptr<Node> &r) :
data(d), color(c), parent(p), left(l), right(r) {}
pair<size_t, T> data;
Color color;
shared_ptr<Node> parent = nullptr;
shared_ptr<Node> left = nullptr;
shared_ptr<Node> right = nullptr;
};
shared_ptr<Node> NIL = std::make_shared<Node>(Black);
shared_ptr<Node> Root = NIL;
public:
RBT() = default;
~RBT() = default;
size_t Hash_Val(const T &x) {
return std::hash<T>()(x);
}
void Inorder_Tree_Walk(const shared_ptr<Node> &p) {
if (p != NIL) {
Inorder_Tree_Walk(p->left);
cout << p->data.second << " ";
if (p->color == Black)
cout << "Black " << endl;
else
cout << "Red " << endl;
Inorder_Tree_Walk(p->right);
}
}
void Inorder_Tree_Walk() {
auto p = Root;
if (p != NIL) {
Inorder_Tree_Walk(p->left);
cout << p->data.second << " ";
if (p->color == Black)
cout << "Black " << endl;
else
cout << "Red " << endl;
Inorder_Tree_Walk(p->right);
}
}
void Preorder_Tree_Walk(const shared_ptr<Node> &p) {
if (p != NIL) {
cout << p->data.second << " ";
if (p->color == Black)
cout << "Black " << endl;
else
cout << "Red " << endl;
Preorder_Tree_Walk(p->left);
Preorder_Tree_Walk(p->right);
}
}
void Preorder_Tree_Walk() {
auto p = Root;
if (p != NIL) {
cout << p->data.second << " ";
if (p->color == Black)
cout << "Black " << endl;
else
cout << "Red " << endl;
Preorder_Tree_Walk(p->left);
Preorder_Tree_Walk(p->right);
}
}
void Postorder_Tree_Walk(const shared_ptr<Node> &p) {
if (p != NIL) {
Postorder_Tree_Walk(p->left);
Postorder_Tree_Walk(p->right);
cout << p->data.second << " ";
if (p->color == Black)
cout << "Black " << endl;
else
cout << "Red " << endl;
}
}
void Postorder_Tree_Walk() {
auto p = Root;
if (p != NIL) {
Postorder_Tree_Walk(p->left);
Postorder_Tree_Walk(p->right);
cout << p->data.second << " ";
if (p->color == Black)
cout << "Black " << endl;
else
cout << "Red " << endl;
}
}
shared_ptr<Node> Tree_Successor(const T &x) {
auto p = Search(x);
if (p->right != NIL) {
return Tree_Successor(p->right->data.second);
}
auto y = p->parent;
while (y != NIL && p == y->right) {
p = y;
y = y->parent;
}
return y;
}
shared_ptr<Node> Tree_Predecessor(const T &x) {
auto p = Search(x);
if (p->left != NIL) {
return Tree_Predecessor(p->left->data.second);
}
auto y = p->parent;
while (y != NIL && p == y->left) {
p = y;
y = y->parent;
}
return y;
}
shared_ptr<Node> Tree_Maximum(const shared_ptr<Node> &Root) {
auto p = Root;
while (p->right != NIL) {
p = p->right;
}
return p;
}
shared_ptr<Node> Tree_Minimum(const shared_ptr<Node> &Root) {
auto p = Root;
while (p->left != NIL) {
p = p->left;
}
return p;
}
void Left_Rotate(shared_ptr<Node> Px) {
auto Py = Px->right;
Px->right = Py->left;
if (Py->left != NIL) {
Py->left->parent = Px;
}
Py->parent = Px->parent;
if (Px->parent == NIL) {
Root = Py;
}
else if (Px == Px->parent->left) {
Px->parent->left = Py;
}
else {
Px->parent->right = Py;
}
Py->left = Px;
Px->parent = Py;
}
void Right_Rotate(shared_ptr<Node> Py) {
auto Px = Py->left;
Py->left = Px->right;
if (Px->right != NIL) {
Px->right->parent = Py;
}
Px->parent = Py->parent;
if (Py->parent == NIL) {
Root = Px;
}
else if (Py == Py->parent->left) {
Py->parent->left = Px;
}
else {
Py->parent->right = Px;
}
Px->right = Py;
Py->parent = Px;
}
void Transplant(const shared_ptr<Node> &p1, const shared_ptr<Node> &P2) {
if (p1->parent == NIL) {
Root = P2;
}
else if (p1 == p1->parent->left) {
p1->parent->left = P2;
}
else {
p1->parent->right = P2;
}
P2->parent = p1->parent;
}
shared_ptr<Node> Search(const T &x) {
auto temp = Hash_Val(x);
auto p = Root;
while (p != NIL && temp != p->data.first) {
if (temp < p->data.first) {
p = p->left;
}
else {
p = p->right;
}
}
try {
if (p == NIL) {
throw std::runtime_error("The element was not found.");
}
}
catch (std::runtime_error err) {
cout << err.what() << endl;
}
return p;
}
void Insert(const T &x) {
auto temp = Hash_Val(x);
shared_ptr<Node> New = std::make_shared<Node>(std::make_pair(temp, x), Red, NIL, NIL, NIL);
auto Px = Root, Py = NIL;
while (Px != NIL) {
Py = Px;
if (temp < Px->data.first) {
Px = Px->left;
}
else {
Px = Px->right;
}
}
New->parent = Py;
if (Py == NIL) {
Root = New;
}
else if (temp < Py->data.first) {
Py->left = New;
}
else {
Py->right = New;
}
Rb_Insert_Fixup(New);
}
void Rb_Insert_Fixup(shared_ptr<Node> &p) {
while (p->parent->color == Red) {
if (p->parent == p->parent->parent->left) {
auto Py = p->parent->parent->right;
if (Py->color == Red) {
p->parent->color = Black;
Py->color = Black;
p->parent->parent->color = Red;
p = p->parent->parent;
}
else {
if (p == p->parent->right) {
p = p->parent;
Left_Rotate(p);
}
p->parent->color = Black;
p->parent->parent->color = Red;
Right_Rotate(p->parent->parent);
}
}
else {
auto Py = p->parent->parent->left;
if (Py->color == Red) {
p->parent->color = Black;
Py->color = Black;
p->parent->parent->color = Red;
p = p->parent->parent;
}
else {
if (p == p->parent->left) {
p = p->parent;
Right_Rotate(p);
}
p->parent->color = Black;
p->parent->parent->color = Red;
Left_Rotate(p->parent->parent);
}
}
}
Root->color = Black;
}
void Delete(const T &x) {
auto p = Search(x);
auto Py = p;
shared_ptr<Node> Px;
Color y_original_color = Py->color;
if (p != NIL) {
if (p->left == NIL) {
Px = p->right;
Transplant(p, p->right);
}
else if (p->right == NIL) {
Px = p->left;
Transplant(p, p->left);
}
else {
Py = Tree_Minimum(p->right);
y_original_color = Py->color;
Px = Py->right;
if (Py->parent == p) {
Px->parent = Py;
}
else {
Transplant(Py, Py->right);
Py->right = p->right;
Py->right->parent = Py;
}
Transplant(p, Py);
Py->left = p->left;
Py->left->parent = Py;
Py->color = p->color;
}
if (y_original_color == Black) {
Rb_Delete_Fixup(Px);
}
}
}
void Rb_Delete_Fixup(shared_ptr<Node> &p) {
while (p != Root && p->color == Black) {
if (p == p->parent->left) {
auto w = p->parent->right;
if (w->color == Red) {
w->color = Black;
p->parent->color = Red;
Left_Rotate(p->parent);
w = p->parent->right;
}
if (w->left->color == Black && w->right->color == Black) {
w->color = Red;
p = p->parent;
}
else {
if (w->right->color == Black) {
w->left->color = Black;
w->color = Red;
Right_Rotate(w);
w = p->parent->right;
}
w->color = p->parent->color;
p->parent->color = Black;
w->right->color = Black;
Left_Rotate(p->parent);
p = Root;
}
}
else {
auto w = p->parent->left;
if (w->color == Red) {
w->color = Black;
p->parent->color = Red;
Right_Rotate(p->parent);
w = p->parent->left;
}
if (w->right->color == Black && w->left->color == Black) {
w->color = Red;
p = p->parent;
}
else {
if (w->left->color == Black) {
w->right->color = Black;
w->color = Red;
Left_Rotate(w);
w = p->parent->right;
}
w->color = p->parent->color;
p->parent->color = Black;
w->left->color = Black;
Right_Rotate(p->parent);
p = Root;
}
}
}
p->color = Black;
}
size_t Tree_Hight(const shared_ptr<Node> &p) {
if (p != NIL) {
size_t left = Tree_Hight(p->left);
size_t right = Tree_Hight(p->right);
if (left > right) {
return left + 1;
}
else {
return right + 1;
}
}
else {
return 0;
}
}
size_t Tree_Hight() {
return Tree_Hight(Root);
}
};
#endif // !RED_BLACK_TREE_X86_H