文章目录
红黑树
所有平衡树 不同的地方 就是对于平衡条件的定义 ---- 如何想出一个均衡 的平衡条件 (对各个操作时间复杂度的均衡,以及空间的优化)。 红黑树是一个不错的选择。
红黑树的平衡条件:
(1)每个节点或者是黑色,或者是红色。
(2)根节点是黑色。
(3)每个叶子节点(NIL)是黑色。 [注意:这里叶子节点,是指为空(NIL或NULL)的叶子节点!]
(4)如果一个节点是红色的,则它的子节点必须是黑色的。
(5)从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。
符合这些条件下 红黑树的高度上界是 2 l o g ( N + 1 ) 2log(N+1) 2log(N+1)
红黑树具体实现(数组实现):
红黑树的节点定义:
struct node
{
int fa;//父节点
int son[2];//子节点
int color;//颜色
int data;//存储的值
int sum;//子树的数量
int count;//出现的次数
};
左旋以及右旋操作:
大家都会吧!
红黑树插入操作(自底向上的插入操作)
回顾红黑树的平衡条件
(1)每个节点或者是黑色,或者是红色。
(2)根节点是黑色。
(3)每个叶子节点(NIL)是黑色。 [注意:这里叶子节点,是指为空(NIL或NULL)的叶子节点!]
(4)如果一个节点是红色的,则它的子节点必须是黑色的。
(5)从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。
首先找到需要插入的位置:建立新节点 并把这个节点染成红色,为什么染成红色,个人认为染成黑色也是可以的,但是后面的讨论和染成红色的有异罢了,这里为了方便 将节点染成红色
Case 1:当前为空子树 直接把该点插入 并把颜色改成黑色
Case 2:被插入节点的父节点是黑色节点 那么什么都不用做 直接插入即可
Case 3: 插入节点已经存在 直接count++即可
Case 4: 当父节点是红色时 需要我们进行仔细讨论如何调整以满足平衡条件
情形1:叔叔节点 也是红色
策略:将父节点 和 叔叔节点 设置为红色 然后 将当前操作节点跳到 祖父节点
下面探讨 父节点 在 曾父节点 的左侧情形 (右侧是左侧的镜像操作就不讲了)
注意这里曾父节点一定是黑色的 性质4
情形2:叔叔节点时黑色(黑色就是包括存在且为黑色 和 不存在) 当前节点为父节点的右孩子
这里可以将 子节点染成黑色 然后再对父节点进行单旋 这样需要再对父节点进行判断 ---- 但是向上调整的过程可以将树结构变得更加平衡 可以说 两种做法更有优劣吧。 具体效率如何还有待测试。
情形3:叔叔节点是黑色 且 当前节点是父节点的左孩子
策略: 对当前节点经行单旋 然后再将当前节点变为父节点 这样就把问题转化为 上一个情形
红黑树删除操作
平衡树的删除操作大体都相似:找到节点 删除 然后进行自平衡操作
删除的具体操作又是替换操作
所以对于删除操作来看 我们可以看作是删除替换节点
而替换节点又只能是叶子节点 这样对我们的分析大大的简化了
对于删除操作来说 主要需要维护的平衡条件是
(5)从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。
Case 1:替换节点是红色节点 没有影响 直接删除
Case 2:替换节点是黑色节点
情形1:替换节点的兄弟节点是红色
在这一情形下替换节点的父节点 和 兄弟节点的子节点 颜色一定是黑色
情形2:替换节点的兄弟节点是黑色
对于这一种情形 需要我们进行讨论 因为我们无法确定其他几个节点的颜色
1.兄弟节点的右子节点是红色,兄弟节点的左子节点是任意颜色
删除替换节点后 右子树的黑色点数量将会减1 所以需要想办法 找一个红色点 变为黑色点填补上去
2.兄弟节点的右子节点是黑色,左子节点是红色
3.兄弟节点的子节点都是黑色
既然子节点无法帮忙了 那么就找父节点帮忙
如果父节点是黑色 继续对父节点进行替换节点的删除自调整
如果父节点是红色 则将父节点颜色变为黑色即可
、