一、红黑树的介绍
红黑树是特殊的二叉查找树,意味着它满足二叉查找树的特征:任意一个节点所包含的键值,大于等于左孩子的键值,小于等于右孩子的键值、除了具备该特性之外,红黑树还包括许多额外的信息。
红黑树的每个节点上都有存储位表示节点的颜色,颜色是红(Red)或黑(Black)。
红黑树的特性:
(1) 每个节点或者是黑色,或者是红色。
(2) 根节点是黑色。
(3) 每个叶子节点是黑色。 [注意:这里叶子节点,是指为空的叶子节点!]
(4) 如果一个节点是红色的,则它的子节点必须是黑色的。
(5) 从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。
关于它的特性,需要注意的是:
第一,特性(3)中的叶子节点,是只为空(NIL或null)的节点。
第二,特性(5),确保没有一条路径会比其他路径长出俩倍。因而,红黑树是相对是接近平衡的二叉树。
红黑树示意图如下:
![](https://i-blog.csdnimg.cn/blog_migrate/4f0584171f1d4836c2cb034768f35642.png)
二、红黑树的C++实现(代码说明)
红黑树的基本操作是添加、删除和旋转。在对红黑树进行添加或删除后,会用到旋转方法。为什么呢?道理很简单,添加或删除红黑树中的节点之后,红黑树就发生了变化,可能不满足红黑树的5条性质,也就不再是一颗红黑树了,而是一颗普通的树。而通过旋转,可以使这颗树重新成为红黑树。简单点说,旋转的目的是让树保持红黑树的特性。
旋转包括两种:左旋 和 右旋。下面分别对红黑树的基本操作进行介绍。
1. 基本定义
enum RBTColor{RED, BLACK};
template <class T>
class RBTNode{
public:
RBTColor color; // 颜色
T key; // 关键字(键值)
RBTNode *left; // 左孩子
RBTNode *right; // 右孩子
RBTNode *parent; // 父结点
RBTNode(T value, RBTColor c, RBTNode *p, RBTNode *l, RBTNode *r):
key(value),color(c),parent(),left(l),right(r) {}
};
template <class T>
class RBTree {
private:
RBTNode<T> *mRoot; // 根结点
public:
RBTree();
~RBTree();
// 前序遍历"红黑树"
void preOrder();
// 中序遍历"红黑树"
void inOrder();
// 后序遍历"红黑树"
void postOrder();
// (递归实现)查找"红黑树"中键值为key的节点
RBTNode<T>* search(T key);
// (非递归实现)查找"红黑树"中键值为key的节点
RBTNode<T>* iterativeSearch(T key);
// 查找最小结点:返回最小结点的键值。
T minimum();
// 查找最大结点:返回最大结点的键值。
T maximum();
// 找结点(x)的后继结点。即,查找"红黑树中数据值大于该结点"的"最小结点"。
RBTNode<T>* successor(RBTNode<T> *x);
// 找结点(x)的前驱结点。即,查找"红黑树中数据值小于该结点"的"最大结点"。
RBTNode<T>* predecessor(RBTNode<T> *x);
// 将结点(key为节点键值)插入到红黑树中
void insert(T key);
// 删除结点(key为节点键值)
void remove(T key);
// 销毁红黑树
void destroy();
// 打印红黑树
void print();
private:
// 前序遍历"红黑树"
void preOrder(RBTNode<T>* tree) const;
// 中序遍历"红黑树"
void inOrder(RBTNode<T>* tree) const;
// 后序遍历"红黑树"
void postOrder(RBTNode<T>* tree) const;
// (递归实现)查找"红黑树x"中键值为key的节点
RBTNode<T>* search(RBTNode<T>* x, T key) const;
// (非递归实现)查找"红黑树x"中键值为key的节点
RBTNode<T>* iterativeSearch(RBTNode<T>* x, T key) const;
// 查找最小结点:返回tree为根结点的红黑树的最小结点。
RBTNode<T>* minimum(RBTNode<T>* tree);
// 查找最大结点:返回tree为根结点的红黑树的最大结点。
RBTNode<T>* maximum(RBTNode<T>* tree);
// 左旋
void leftRotate(RBTNode<T>* &root, RBTNode<T>* x);
// 右旋
void rightRotate(RBTNode<T>* &root, RBTNode<T>* y);
// 插入函数
void insert(RBTNode<T>* &root, RBTNode<T>* node);
// 插入修正函数
void insertFixUp(RBTNode<T>* &root, RBTNode<T>* node);
// 删除函数
void remove(RBTNode<T>* &root, RBTNode<T> *node);
// 删除修正函数
void removeFixUp(RBTNode<T>* &root, RBTNode<T> *node, RBTNode<T> *parent);
// 销毁红黑树
void destroy(RBTNode<T>* &tree);
// 打印红黑树
void print(RBTNode<T>* tree, T key, int direction);
#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)
};
2. 左旋