特点:
不是一颗平衡树,左右子树的高度差,长的不超过短的2倍。
- 树的每一个节点都有颜色
- NULL是黑色
- root是黑色
- 不能出现连续的红色节点
- 从root根节点到每一个叶子节点的路径上,黑色节点的数量是相同的
从上图中可以看出,对于只需要增、查操作的话,AVL树要更好一些。但是对于大数据量,并且需要删除操作,那么红黑树整体下来性能要更好,因为旋转的次数要更少些。所以,为什么stl会选择红黑树作为set、map容器的底层数据结构。
插入操作
- 如果是空树,则直接插入作为根节点, 节点颜色: [黑色]
- 如果非空树,插入节点为叶子节点, 节点颜色: [红色]. 此时要检查父节点的颜色,如果父节点颜色是黑色,插入完成。否则出现连续的红色节点,开始做插入调整。
以下只是一侧的情况,左侧和右侧加一起一共有六种情况
情况1:
情况2:
情况3:
将左子树都变为一侧然后以情况2处理
插入代码:
代码中的每一个情况都是以上图而编写,熟练写几遍,脑子里能记住上面几个图,代码就很容易写出来了。
template <typename T>
class RBTree
{
enum Color { BLACK = 1, RED }; // 定义颜色
struct Node; // 声明结构体类型
public:
RBTree() {}
~RBTree() { /* 三种遍历方式进行析构 */ }
void insert(const T& data) // 插入函数
{
if (m_root == nullptr)
{
// 根节点为空,插入元素作为根节点
m_root = new Node(data);
return;
}
Node* curr = m_root;
Node* p = nullptr;
while (curr)
{
p = curr;
if (data > curr->data) // 插入的元素比当前元素小
curr = curr->right; // 往右子树遍历
else if (data < curr->data) // 插入的元素比当前元素大
curr = curr->left; // 往左子树遍历
else return; // 如果存在该元素则不插入退出函数
}
Node* node = new Node(data, RED, p); // 生成一个节点,颜色为红色
if (data > p->data) // 向右子树插入节点
parent(node)->right = node;
else parent(node)->left = node; // 向左子树插入节点
if (color(parent(node)) == RED)
fixAfterInsert(node); // 当前节点和父节点都为红色则需要调整
}
private:
// 以下为几个便捷的函数
inline void setParent(Node* node, Node* parent) { node->parent = parent; }
inline Node* parent(Node* node) { return node->parent; }
inline Color color(Node* node)
{ return node == nullptr ? BLACK : node->color; }
inline void setColor(Node* node, Color color)
{ if (!node) return; node->color = color; }
private:
// 插入元素需要调整
void fixAfterInsert(Node* node)
{
while (color(parent(node)) == RED)
{
if (parent(parent(node))->left == parent(node))
{
// 插入的节点在左子树
Node* uncle = parent(parent(node))->right;
if (color(uncle) == BLACK)
{
// 情况3
if (parent(node)->right == node)
{
node = parent(node);
leftRotate(node);
}
// 情况2
setColor(parent(node), BLACK);
setColor(parent(parent(node)), RED);
rightRotate(parent(parent(node)));
break; // 调整完成
}
// 情况1
setColor(parent(node), BLACK);
setColor(parent(parent(node)), RED);
setColor(uncle, BLACK);
node = parent(parent(node)); // 以爷爷节点继续向上回溯
}
else
{
// 插入的节点在右子树
Node* uncle = parent(parent(node))->left;
if (color(uncle) == BLACK)
{
// 情况3
if (parent(node)->left == node)
{
node = parent(node);
rightRotate(node);
}
// 情况2
setColor(parent(node), BLACK);
setColor(parent(parent(node)), RED);
leftRotate(parent(parent(node)));
break; // 调整完成
}
// 情况1
setColor(parent(node), BLACK);
setColor(parent(parent(node)), RED);
setColor(uncle, BLACK);
node = parent(parent(node)); // 以爷爷节点继续向上回溯
}
}
setColor(m_root, BLACK);
}
};
测试代码
int main()
{
RBTree<int> tree;
for (int i = 0; i < 10; i++)
tree.insert(i);
return 0;
}