红黑树详解
什么是红黑树?
红黑树,是一种二叉搜索树的特化,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出两倍,因而是接近平衡的。
红黑树和AVL树都是高效的平衡二叉树,增删改查的时间复杂度都是O(logN),红黑树不追求绝对平衡,其只需保证最长路径不超过最短路径的2倍,相对而言,降低了插入和旋转的次数,所以在经常进行增删的结构中性能比AVL树更优,而且红黑树实现比较简单,所以实际运用中红黑树更多。
红黑树的性质
- 每个结点不是红色就是黑色
- 根节点是黑色的,如果一个节点是红色的则它的两个孩子结点是黑色的
- 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均 包含相同数目的黑色结点
- 每个叶子结点都是黑色的**(此处的叶子结点指的是空结点)**
为什么满足以上性质的二叉树就可以满足最短路径长度小于等于最长路径长度的两倍呢?
在极端情况下,根据性质2和3,假设一条路径全为黑色节点,另一条路径黑红节点交错,此时是满足最短路径长度小于等于最长路径长度的两倍的,其他非极端条件下也同样满足。
红黑树的实现
0.红黑树的节点
由左右父三个节点的指针、保存的数据val、节点的颜色组成
class RBTNode
{
public:
RBTNode<T>* _left;
RBTNode<T>* _right;
RBTNode<T>* _parent;
T val;
color _col;
RBTNode(const T& v)
:_left(nullptr)
,_right(nullptr)
,_parent(nullptr)
,val(v)
{}
};
1.红黑树的插入操作
我们假设原红黑树是正确的,假设插入节点是黑色节点,它会破坏性质3,这种破坏想要重新调整为红黑树是十分困难的,原因是它要控制每条路径黑节点的数量,因此对每条路径都要调整,而假如插入节点是红色节点,那么只需要对有限个节点进行变色+旋转就可以把树重新调整为红黑树。
因此这里我们假定插入节点是红色节点。
这里把红黑树的插入分为三种情况:
定义:当前节点,父节点(当前节点的父亲),舅节点(父节点的兄弟节点),祖父节点(父节点的父节点)
1.插入节点的父节点是黑节点:此时没有违反红黑树的任何一条性质,直接按照AVL树的插入性质进行插入就可以。
2.插入节点的父节点是红节点,舅节点不存在或存在但为黑节点