Files
DataStruct/include/RedBlackTree.h

624 lines
20 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 版权所有 (c) ling 保留所有权利。
// 除非另行说明否则仅允许在DataStruct中使用此文件中的代码。
//
// 由 ling 创建于 24-6-30.
//
#ifndef REDBLACKTREE_REDBLACKTREE_H_03
#define REDBLACKTREE_REDBLACKTREE_H_03
#include <cstddef>
#include <stack>
namespace ling {
enum Relation {
EQUAL,
BIG,
SMALL,
};
enum Color {
RED,
BLACK,
};
/**
* 红黑树
* @tparam T
*/
template<typename T>
class RedBlackTree {
public:
struct Node {
T value;
Color color;
Node *left;
Node *right;
//父节点
Node *parent;
Node(T value, Color c, Node *p, Node *l, Node *r) : value(value), color(c), parent(p), left(l), right(r) {
}
};
private:
/// 根节点
Node *rootNode = nullptr;
void destroy(Node *&node);
/// 插入函数
void insert(Node *&root, Node *node);
/**
* 红黑树插入修正函数
*
* 在向红黑树中插入节点之后(失去平衡),再调用该函数;
* 目的是将它重新塑造成一颗红黑树。
*
* @param root 红黑树的根
* @param node 插入的结点
*/
void insertFixUp(Node *&root, Node *node);
/**
* 红黑树删除修正函数
*
* 在从红黑树中删除插入节点之后(红黑树失去平衡),再调用该函数;
* 目的是将它重新塑造成一颗红黑树。
*
* @param root 红黑树的根
* @param node 待修正的节点
*/
void removeFixUp(Node *&root, Node *node, Node *parent);
/**
* 对红黑树的节点(x)进行左旋转
*
* 左旋示意图(对节点x进行左旋)
* px px
* / /
* x y
* / \ --(左旋)--> / \ #
* lx y x ry
* / \ / \
* ly ry lx ly
*
*
*/
void leftRotate(Node *&root, Node *x);
/**
* 对红黑树的节点(y)进行右旋转
*
* 右旋示意图(对节点y进行左旋)
* py py
* / /
* y x
* / \ --(右旋)--> / \ #
* x ry lx y
* / \ / \ #
* lx rx rx ry
*
*/
void rightRotate(Node *&root, Node *y);
/// 查找元素
Node *iterativeSearch(Node *x, T key) const;
Node *findSearch(Node *x, T key) const;
/// 删除元素
void remove(Node *&root, Node *node);
protected:
virtual Relation equal(const T &val1, const T &val2) const = 0;
public:
explicit RedBlackTree() = default;
virtual ~RedBlackTree() {
destroy();
}
/// 销毁红黑树
void destroy();
/// 插入元素
void insert(T key);
/// 删除节点
void remove(T key);
/// 查找元素
/// 区别于findSearch此方法会在没有匹配时返回接近的节点
const Node *iterativeSearch(T key) const;
const Node *findSearch(T key) const;
/// 根节点
const Node *getRoot() const {
return rootNode;
}
// 查找最小结点返回tree为根结点的红黑树的最小结点。
const Node *minimum() const;
// 查找最大结点返回tree为根结点的红黑树的最大结点。
const Node *maximum() const;
[[nodiscard]] size_t getSize() const;
[[nodiscard]] int getTreeHeight() const;
#define rb_parent(r) ((r)->parent)
#define rb_color(r) ((r)->color)
#define rb_is_red(r) ((r)->color==RED)
#define rb_is_black(r) ((r)->color==BLACK)
#define rb_set_black(r) do { (r)->color = BLACK; } while (0)
#define rb_set_red(r) do { (r)->color = RED; } while (0)
#define rb_set_parent(r, p) do { (r)->parent = (p); } while (0)
#define rb_set_color(r, c) do { (r)->color = (c); } while (0)
};
template<typename T>
int RedBlackTree<T>::getTreeHeight() const {
const Node *current = getRoot();
if (current == nullptr)
return 0;
std::stack<std::pair<const Node *, int>> stack;
stack.push({current, 1});
int maxHeight = 0;
while (!stack.empty()) {
auto [node, height] = stack.top();
stack.pop();
if (node != nullptr) {
maxHeight = std::max(maxHeight, height);
if (node->right != nullptr) {
stack.push({node->right, height + 1});
}
if (node->left != nullptr) {
stack.push({node->left, height + 1});
}
}
}
return maxHeight;
}
template<typename T>
size_t RedBlackTree<T>::getSize() const {
const Node *current = getRoot();
std::stack<const Node *> stack;
size_t size = 0;
while (current != nullptr || !stack.empty()) {
//走到最坐子树
while (current != nullptr) {
stack.push(current);
current = current->left;
}
//处理当前节点
current = stack.top();
stack.pop();
size++;
//处理右子树
current = current->right;
}
return size;
}
template<typename T>
typename RedBlackTree<T>::Node const *RedBlackTree<T>::maximum() const {
Node *tree = rootNode;
if (tree == nullptr)
return nullptr;
while (tree->right != nullptr)
tree = tree->right;
return tree;
}
template<typename T>
typename RedBlackTree<T>::Node const *RedBlackTree<T>::minimum() const {
Node *tree = rootNode;
if (tree == nullptr)
return nullptr;
while (tree->left != nullptr)
tree = tree->left;
return tree;
}
template<typename T>
void RedBlackTree<T>::removeFixUp(RedBlackTree::Node *&root, RedBlackTree::Node *node, RedBlackTree::Node *parent) {
Node *other;
while ((!node || rb_is_black(node)) && node != root) {
if (parent->left == node) {
other = parent->right;
if (rb_is_red(other)) {
// Case 1: x的兄弟w是红色的
rb_set_black(other);
rb_set_red(parent);
leftRotate(root, parent);
other = parent->right;
}
if ((!other->left || rb_is_black(other->left)) &&
(!other->right || rb_is_black(other->right))) {
// Case 2: x的兄弟w是黑色且w的俩个孩子也都是黑色的
rb_set_red(other);
node = parent;
parent = rb_parent(node);
} else {
if (!other->right || rb_is_black(other->right)) {
// Case 3: x的兄弟w是黑色的并且w的左孩子是红色右孩子为黑色。
rb_set_black(other->left);
rb_set_red(other);
rightRotate(root, other);
other = parent->right;
}
// Case 4: x的兄弟w是黑色的并且w的右孩子是红色的左孩子任意颜色。
rb_set_color(other, rb_color(parent));
rb_set_black(parent);
rb_set_black(other->right);
leftRotate(root, parent);
node = root;
break;
}
} else {
other = parent->left;
if (rb_is_red(other)) {
// Case 1: x的兄弟w是红色的
rb_set_black(other);
rb_set_red(parent);
rightRotate(root, parent);
other = parent->left;
}
if ((!other->left || rb_is_black(other->left)) &&
(!other->right || rb_is_black(other->right))) {
// Case 2: x的兄弟w是黑色且w的俩个孩子也都是黑色的
rb_set_red(other);
node = parent;
parent = rb_parent(node);
} else {
if (!other->left || rb_is_black(other->left)) {
// Case 3: x的兄弟w是黑色的并且w的左孩子是红色右孩子为黑色。
rb_set_black(other->right);
rb_set_red(other);
leftRotate(root, other);
other = parent->left;
}
// Case 4: x的兄弟w是黑色的并且w的右孩子是红色的左孩子任意颜色。
rb_set_color(other, rb_color(parent));
rb_set_black(parent);
rb_set_black(other->left);
rightRotate(root, parent);
node = root;
break;
}
}
}
if (node)
rb_set_black(node);
}
template<typename T>
void RedBlackTree<T>::remove(RedBlackTree::Node *&root, RedBlackTree::Node *node) {
Node *child, *parent;
Color color;
// 被删除节点的"左右孩子都不为空"的情况。
if ((node->left != nullptr) && (node->right != nullptr)) {
// 被删节点的后继节点。(称为"取代节点")
// 用它来取代"被删节点"的位置,然后再将"被删节点"去掉。
Node *replace = node;
// 获取后继节点
replace = replace->right;
while (replace->left != nullptr)
replace = replace->left;
// "node节点"不是根节点(只有根节点不存在父节点)
if (rb_parent(node)) {
if (rb_parent(node)->left == node)
rb_parent(node)->left = replace;
else
rb_parent(node)->right = replace;
} else
// "node节点"是根节点,更新根节点。
root = replace;
// child是"取代节点"的右孩子,也是需要"调整的节点"。
// "取代节点"肯定不存在左孩子!因为它是一个后继节点。
child = replace->right;
parent = rb_parent(replace);
// 保存"取代节点"的颜色
color = rb_color(replace);
// "被删除节点"是"它的后继节点的父节点"
if (parent == node) {
parent = replace;
} else {
// child不为空
if (child)
rb_set_parent(child, parent);
parent->left = child;
replace->right = node->right;
rb_set_parent(node->right, replace);
}
replace->parent = node->parent;
replace->color = node->color;
replace->left = node->left;
node->left->parent = replace;
if (color == BLACK)
removeFixUp(root, child, parent);
delete node;
return;
}
if (node->left != nullptr)
child = node->left;
else
child = node->right;
parent = node->parent;
// 保存"取代节点"的颜色
color = node->color;
if (child)
child->parent = parent;
// "node节点"不是根节点
if (parent) {
if (parent->left == node)
parent->left = child;
else
parent->right = child;
} else
root = child;
if (color == BLACK)
removeFixUp(root, child, parent);
delete node;
}
template<typename T>
typename RedBlackTree<T>::Node *RedBlackTree<T>::iterativeSearch(RedBlackTree::Node *x, T key) const {
Relation temp;
Node *closest = nullptr;
while (x != nullptr) {
temp = equal(x->value, key);
if (temp == EQUAL)
return x;
if (temp == SMALL) {
closest = x;
x = x->right;
} else {
x = x->left;
}
}
return closest;
}
template<typename T>
typename RedBlackTree<T>::Node *RedBlackTree<T>::findSearch(RedBlackTree::Node *x, T key) const {
while ((x != nullptr) && equal(x->value, key) != EQUAL) {
if (equal(key, x->value) == SMALL) {
x = x->left;
} else {
x = x->right;
}
}
return x;
}
template<typename T>
typename RedBlackTree<T>::Node const *RedBlackTree<T>::findSearch(T key) const {
return findSearch(rootNode, key);
}
template<typename T>
typename RedBlackTree<T>::Node const *RedBlackTree<T>::iterativeSearch(T key) const {
return iterativeSearch(rootNode, key);
}
template<typename T>
void RedBlackTree<T>::remove(T key) {
Node *node;
// 查找key对应的节点(node),找到的话就删除该节点
if ((node = iterativeSearch(rootNode, key)) != nullptr)
remove(rootNode, node);
}
template<typename T>
void RedBlackTree<T>::rightRotate(RedBlackTree::Node *&root, RedBlackTree::Node *y) {
// 设置x是当前节点的左孩子。
Node *x = y->left;
// 将 “x的右孩子” 设为 “y的左孩子”
// 如果"x的右孩子"不为空的话,将 “y” 设为 “x的右孩子的父亲”
y->left = x->right;
if (x->right != nullptr)
x->right->parent = y;
// 将 “y的父亲” 设为 “x的父亲”
x->parent = y->parent;
if (y->parent == nullptr) {
root = x; // 如果 “y的父亲” 是空节点则将x设为根节点
} else {
if (y == y->parent->right)
y->parent->right = x; // 如果 y是它父节点的右孩子则将x设为“y的父节点的右孩子”
else
y->parent->left = x; // (y是它父节点的左孩子) 将x设为“x的父节点的左孩子”
}
// 将 “y” 设为 “x的右孩子”
x->right = y;
// 将 “y的父节点” 设为 “x”
y->parent = x;
}
template<typename T>
void RedBlackTree<T>::leftRotate(RedBlackTree::Node *&root, RedBlackTree::Node *x) {
// 设置x的右孩子为y
Node *y = x->right;
// 将 “y的左孩子” 设为 “x的右孩子”
// 如果y的左孩子非空将 “x” 设为 “y的左孩子的父亲”
x->right = y->left;
if (y->left != nullptr)
y->left->parent = x;
// 将 “x的父亲” 设为 “y的父亲”
y->parent = x->parent;
if (x->parent == nullptr) {
root = y; // 如果 “x的父亲” 是空节点则将y设为根节点
} else {
if (x->parent->left == x)
x->parent->left = y; // 如果 x是它父节点的左孩子则将y设为“x的父节点的左孩子”
else
x->parent->right = y; // 如果 x是它父节点的左孩子则将y设为“x的父节点的左孩子”
}
// 将 “x” 设为 “y的左孩子”
y->left = x;
// 将 “x的父节点” 设为 “y”
x->parent = y;
}
template<typename T>
void RedBlackTree<T>::insertFixUp(RedBlackTree::Node *&root, RedBlackTree::Node *node) {
Node *parent;
Node *gparent;
// 若父节点存在,并且父节点的颜色是红色
while ((parent = rb_parent(node)) && rb_is_red(parent)) {
gparent = rb_parent(parent);
//若父节点是祖父节点的左孩子
//若“父节点”是“祖父节点的左孩子”
if (parent == gparent->left) {
// Case 1条件叔叔节点是红色
{
Node *uncle = gparent->right;
if (uncle && rb_is_red(uncle)) {
rb_set_black(uncle);
rb_set_black(parent);
rb_set_red(gparent);
node = gparent;
continue;
}
}
// Case 2条件叔叔是黑色且当前节点是右孩子
if (parent->right == node) {
Node *tmp;
leftRotate(root, parent);
tmp = parent;
parent = node;
node = tmp;
}
// Case 3条件叔叔是黑色且当前节点是左孩子。
rb_set_black(parent);
rb_set_red(gparent);
rightRotate(root, gparent);
} else//若“z的父节点”是“z的祖父节点的右孩子”
{
// Case 1条件叔叔节点是红色
{
Node *uncle = gparent->left;
if (uncle && rb_is_red(uncle)) {
rb_set_black(uncle);
rb_set_black(parent);
rb_set_red(gparent);
node = gparent;
continue;
}
}
// Case 2条件叔叔是黑色且当前节点是左孩子
if (parent->left == node) {
Node *tmp;
rightRotate(root, parent);
tmp = parent;
parent = node;
node = tmp;
}
// Case 3条件叔叔是黑色且当前节点是右孩子。
rb_set_black(parent);
rb_set_red(gparent);
leftRotate(root, gparent);
}
}
// 将根节点设为黑色
rb_set_black(root);
}
template<typename T>
void RedBlackTree<T>::insert(RedBlackTree::Node *&root, RedBlackTree::Node *node) {
Node *y = nullptr;
Node *x = root;
// 1. 将红黑树当作一颗二叉搜索树,将节点插入二叉搜索树中
while (x != nullptr) {
y = x;
if (equal(node->value, x->value) == SMALL) {
x = x->left;
} else {
x = x->right;
}
}
node->parent = y;
if (y != nullptr) {
if (equal(node->value, y->value) == SMALL) {
y->left = node;
} else {
y->right = node;
}
} else {
root = node;
}
// 2. 设置节点的颜色为红色
node->color = RED;
// 3. 将他重新修正为一颗红黑树
insertFixUp(root, node);
}
template<typename T>
void RedBlackTree<T>::insert(T key) {
Node *node = new Node(key, BLACK, nullptr, nullptr, nullptr);
insert(rootNode, node);
}
template<typename T>
void RedBlackTree<T>::destroy() {
destroy(rootNode);
}
template<typename T>
void RedBlackTree<T>::destroy(RedBlackTree::Node *&node) {
if (node == nullptr)
return;
if (node->left != nullptr)
destroy(node->left);
if (node->right != nullptr)
destroy(node->right);
delete node;
node = nullptr;
}
} // ling
#endif //REDBLACKTREE_REDBLACKTREE_H_03