平衡树 - 红黑树

红黑树

搞了4天,终于AC了…

平衡树是一种非常快的数据结构,比其他平衡树(Splay,Treap,FHQ)快一些

时间复杂度严格在 O ( log ⁡ n ) O(\log n) O(logn) 之内

支持查找、删除、插入、前驱、后缀等操作

红黑树的前生是2-3树,也称B树

自己学去(其实是我懒

红黑树的性质有5个:

  1. 每个节点只有黑色或者红色

  2. 根节点是黑色

  3. NULL节点(空节点)是黑色

  4. 每个红色节点的子节点必须是黑色

  5. 每个节点到他的子树的所有NULL节点的路径上的黑色节点一样多

  6. 从性质5,我们可以推出,每个红色节点必须有两个黑色节点。(空节点也算黑色)

红黑树的插入:

我们插入的节点是什么颜色,当然是红色了,这样最少更改满足性质 5。

插入分为种情况

  1. 此树为空树。

  2. 插入节点的父亲为黑色

  3. 插入节点的父亲为红色

    1. 插入节点的叔叔为红色

    2. 插入节点的叔叔为黑色

      1. 插入节点的父亲是他爷爷的左儿子

      2. 插入节点的父亲是他爷爷的右儿子

I为插入节点,F为父亲节点,G为祖先节点,U为叔叔节点

情况1: 此树为空树

如果这棵树是空树的话,我们直接插入该节点,然后把该节点的颜色改为黑色,然后将该节点设为根节点。

情况2:插入节点的父亲为黑色

直接插入该节点,因为父亲是黑色不会影响到二叉树的性质。

情况3-1:父亲节点是红色,且叔叔节点是红色

我们将父亲节点设为黑色,叔叔节点设为黑色,爷爷节点设为红色。

但是如果爷爷节点的父亲节点是红色的呢?我们就需要对爷爷节点进行操作。

我们可以看作在整棵树里面插入爷爷节点和他的子树,这时候,我们需要对爷爷节点进行插入调整。

情况3-2-1:父亲节点是红色,且叔叔节点是黑色,而且插入节点的父亲是他爷爷的左儿子

我们先把自己变成父亲节点的左儿子。

把自己从右儿子变成左儿子的方法(当然如果已经是左儿子就不用了):

  1. 把自己变成原来的自己的父亲。

  2. 左旋自己。

将父亲颜色设为黑色,将爷爷颜色设为红。

然后右旋。

情况3-2-2:父亲节点是红色,且叔叔节点是黑色,而且插入节点的父亲是他爷爷的右儿子

其实这里处理方法就是上面的翻转:

如果自己是父亲的左儿子:

  1. 把自己变成原来的自己的父亲。

  2. 右旋自己。

将父亲颜色设为黑色,将爷爷颜色设为红。

然后左旋。(图…就不符了…太难画了)

那么我们红黑树的插入就搞定了

红黑树的删除:

删除分为3种情况;

1. 删除节点既有左子树也有右子树。

2. 删除节点只有左子树或者右子树。

3. 删除节点没有左子树没有右子树。

当删除节点左右两颗子树都有的时候,我们直接让删除节点的后继的值赋值给删除节点,然后把后继节点删除(可以看成和后继节点交换后删除原来要删除的节点),这里的删除也要用删除判断。

当删除节点只有一颗子树的时候,还有2种情况:

1. 删除节点有一颗左子树,而且根据性质 5,删除节点一定是黑色,而且左儿子肯定是红色。

2. 删除节点有一颗右子树,而且根据性质 5,删除节点一定是黑色,而且左儿子肯定是红色。

这时候,我们只需要把删除节点删除(直接删除,不用考虑其他问题),然后把左或右子节点改成黑色后替换到删除节点的位置(把子树也提上来)。

当删除节点没有子树,也就是说他是叶子节点的时候,还有4种情况:

  1. 删除节点为红色

  2. 删除节点为黑色

    1. 删除节点的兄弟节点为红色

    2. 删除节点的兄弟节点为黑色

      1. 删除节点的兄弟节点的左右子节点中,至少有一个是红色。

        1. 删除节点是他父亲的左子节点。

        2. 删除节点是他父亲的右子节点。

      2. 删除节点的兄弟节点的左右子节点中,全是黑色。

情况1:删除节点是红色。

我们直接删除,无影响。

情况2:删除节点是黑色且删除节点的兄弟节点为红色。

这时候,我们将父亲节点设为红色,将兄弟节点设为黑色。

然后向父亲节点往删除节点的方向旋转父亲节点。

这时候,这棵树还不是红黑树,我们需要继续判断下面的情况(当判断下面的情况的时候,删除节点不变,但是兄弟节点不是原来的兄弟节点,是当前的)

情况3:删除节点是黑色,删除节点的兄弟节点为黑色,删除节点的兄弟节点的左右子节点中,至少有一个是红色且删除节点是他父亲的左子节点。

这时候我们要兄弟节点的红色子节点调整为兄弟节点的右节点:

如果兄弟节点的左节点是红色,把兄弟节点的左节点都变成黑色,然后把兄弟节点设为红色,再把兄弟节点右旋一下。

然后我们把红色子节点调整后,我们把兄弟节点的颜色设为父亲节点的颜色。

再把父亲节点和兄弟节点的右子节点的颜色都设为黑色。

左旋父亲节点。

情况4:删除节点是黑色,删除节点的兄弟节点为黑色,删除节点的兄弟节点的左右子节点中,至少有一个是红色且删除节点是他父亲的右子节点。

我不多讲了,这跟上面的差不多。

如果兄弟节点的右节点是红色,把兄弟节点的右节点都变成黑色,然后把兄弟节点设为红色,再把兄弟节点左旋一下。

然后我们把红色子节点调整后,我们把兄弟节点的颜色设为父亲节点的颜色。

再把父亲节点和兄弟节点的左节点的颜色都设为黑色。

右旋父亲节点。懒得附图

情况5:删除节点是黑色,删除节点的兄弟节点为黑色,删除节点的兄弟节点的左右子节点中,全是黑色。

太好了,现在兄弟节点没有红色借了。

我们只好把工作交给祖先了,我们把兄弟节点染成红色。

如果父亲是根节点,不用更改。

如果父亲是红色,把父亲设为黑色。

如果父亲是黑色,然后看成是删除父亲,对父亲进行删除调整(很容易理解,因为在父亲这里少了一个黑节点,所以我们可以看作删除父亲)


(还差一个删除 D 节点,懒得搞了)然后呢,我们的删除操作就结束了。

其他操作跟 T r e a p Treap Treap 一样,这里不讲了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值