目录
红黑树是一种自平衡的二叉搜索树,它通过一组规则来确保树在插入或删除操作后保持平衡。这些规则保证了红黑树的高度是 O(logn),从而使得基本操作的时间复杂度也维持在O(logn)。以下是红黑树的基本规则:
红黑树的五大规则
-
节点要么是红色,要么是黑色:
- 这是红黑树的基础,红黑树中的每个节点都被涂上红色或黑色。
-
根节点是黑色:
- 根节点始终是黑色的。这一规则保证了红黑树在插入或删除操作时,从根节点开始的路径符合红黑树的性质。
-
所有叶子节点(NIL节点)是黑色的:
- 红黑树中的叶子节点实际上是指向
NIL
(空节点)的指针,这些叶子节点在红黑树中都被视为黑色。这样做是为了在树的末端保持一致性。所以每个开头祖父结点到nullptr才算一条完整的路径。
- 红黑树中的叶子节点实际上是指向
-
红色节点的子节点必须是黑色(即红色节点不能有红色的子节点):
- 这一规则限制了红色节点的连通性,避免了连续的红色节点,这样可以防止树的某些路径变得过长而导致不平衡。
-
从任意节点到其每个叶子节点的路径上都必须具有相同数量的黑色节点(称为黑色高度):
- 黑色高度指的是从某一节点到其叶子节点的路径上,黑色节点的数量。这个规则保证了树的平衡性,因为在所有路径上的黑色节点数量相同,从而避免了树的某些分支比其他分支明显更深。
这些规则的作用
-
规则1和规则4: 通过颜色的约束,保证没有路径会比其他路径长出两倍,因此限制了树的高度,确保了树是“近似平衡”的。
-
规则2和规则3: 根节点为黑色和所有叶子节点为黑色,确保了树的基础结构的稳定性。
-
规则5: 保证了所有路径的黑色节点数量一致,这一性质非常关键,它确保了树的平衡性,不会有某一条路径比另一条长得太多。
插入和删除中的规则修正(简单了解一下)
在红黑树中,当进行插入或删除操作时,可能会违反上述规则。为了修正这些违规情况,红黑树会进行重新着色和旋转操作,以恢复平衡并满足所有规则。
-
插入修正: 插入一个新节点后,如果这个节点的父节点是红色的,那么可能会违反红黑树的规则。这时需要通过左旋、右旋以及重新着色来恢复规则的平衡。
-
删除修正: 删除一个节点可能会导致路径上的黑色节点数量不一致,这时通过一系列旋转和重新着色来修正。
这些规则和修正机制使得红黑树在进行插入和删除操作后,能够有效地保持自身的平衡性,从而确保其高效的查找、插入和删除操作。
代码实现
enum color
{
RED,
BLACK
};
笔记:因为红黑树只有两种颜色所以可以使用枚举类型color进行表示。
template<class K, class V>
struct RBTreeNode
{
pair<K, V> _kv;
RBTreeNode<K, V>* _left;
RBTreeNode<K, V>* _right;
RBTreeNode<K, V>* _parent;
color _col;
RBTreeNode(const pair<K, V>& kv)
:_kv(kv)
, _left(nullptr)
, _right(nullptr)
, _parent(nullptr)
{}
};
笔记:由于红黑树的本质还是搜索树,所以每个结点还是三叉链的形式即左右结点和父亲结点,用pair(K,V)模型记录每个结点存的数据形式。_col由于不知道要初始化成什么就不进行初始化了。
接着我们看Rbtree这个类,我们实现红黑树还是主要实现insert,还有一些比较次要的东西比如copy,find什么的。
插入结点还是和原本搜索树一样,由于红黑树的特殊规则,头节点必须是黑色的,每条路径的黑结点个数都是一样的,所以我们每次无论在那条路径新插入结点都必须是红色的,这样是为了不破坏当条路径的黑结点个数。
if (_