理解红黑树

国庆成功的浪了8天,中间断断续续的看书,也没啥总结,不过最近在看stl源码剖析,看到了红黑树这一块,红黑树由于其优于二叉树的平衡特性,因而被广泛的使用在各种情况下,值得我们深入理解总结一番.

  1. 红黑树的介绍
    首先,红黑树肯定是属于二叉树的一种,但是由于其优于二叉树的平衡性因而得到了很广泛的应用.红黑树需要满足以下条件:

    • 每个节点不是红色就是黑色
    • 根节点为黑色
    • 如果节点为红,其子节点必须为黑
    • 任意节点至NULL(树尾端)的任何路径,所含之黑节点数比较相同.

    根据规则4,新增节点必须为红,根据规则3,新增节点之父节点必须为黑.当新节点根据二叉树的规则到达其插入点,却未能符合上述条件时,就必须调整颜色并旋转树型.(图片来自stl源码剖析)


    理解红黑树_第1张图片
    image.png

    很显然,由于这些规则的存在,当我们每次插入节点的时候,可能就需要对整个红黑树进行调整,因为其规则的要求,所以红黑树是不可能出现所有子节点都在树的一侧的情况,因而我们可以确信对红黑树的检索和插入和删除操作肯定是可以在log(n)的时间内完成.这也就是红黑树优于普通二叉树的地方.

  2. 插入节点
    对于插入节点,我们需要对各种情况进行分析,因为总共情况是有限种的,这样反而有助于我们的理解,个人觉得这个思路有时候是非常有用的,因为我们在实际问题中,并不是任何问题都能抽象出一个通用的解决问题的模型出来,这样把情况都罗列出来也不失为一种好办法.
    下面图片来自<>stl源码剖析,我会添加个人的一些理解.>,我会添加个人的一些理解.


    理解红黑树_第2张图片
    image.png

    第一种情况,我们的新插入节点为X,显然由我们上面所说的,X的颜色肯定是红色,但是这样的话就违背了红黑树的规则,因为P和X的颜色都是红色.所以我们要对红黑树进行调整,我们所做的是将P,G右旋,再改变P和G的颜色,这样我们就解决了这个节点的插入问题,并且不会影响到树的其他部分,这次插入就完成了.


    理解红黑树_第3张图片
    image.png

    第二种情况,这次由于X是在内侧插入的,所以我们需要两次旋转,先将P和X左旋,再将G和X右旋,这样问题就解决了.实际上和第一次并没有很大区别,只是多了一次旋转.
    理解红黑树_第4张图片
    image.png

    第三种情况下,情况乍一看和情况一是十分类似的,但是有区别的地方在于节点的颜色,如果节点P的父节点是红色的话,我们可能就需要做出更多的一些调整了,我们在状况4中来看看.
    理解红黑树_第5张图片
    image.png

    实际上情况4也并没有很多解释,这书真是坑(笑),实际上我们仔细看看,这个情况和第一,二种情况是有点类似的,都是连续的两个红色节点,我们只需要顺序着往上检查并调整就可以了.

  3. 删除节点
    删除节点相对于插入节点,情况更类似于二叉树一点:

    • 当被删除节点为叶子节点,那么直接删除该节点就OK了.
    • 当被删除节点只有一个孩子节点,那么直接删除该节点,利用该节点的孩子节点直接顶替它的位置.
    • 如果被删除的节点有两个儿子,真正删除的节点应该是所要删除的节点的中序遍历前驱.(也就是小于这个节点的最大节点).

    之后的操作更多的是红黑树为了维护自身特性的操作了,我们需要对红黑树进行旋转和重新着色来维护该树.(图片来自网络,助于理解)


    理解红黑树_第6张图片

    注意在这个图上,我们将23替代为18之后,仍然需要一些旋转和着色操作.(实际上只需要将12,16节点右旋就OK了).

  4. 结语
    本文主要介绍了红黑数的一些特殊的地方,加深记忆,还有剩下的主要是实现了,至于代码的话,如果有童鞋想深入了解了解,我推荐stl源码剖析,值得深入学习,实在为我们这些c++程序员的必读经典.红黑树的应用领域十分广泛,linux下的进程管理就是用的红黑树,set以及map的实现底层也都是基于红黑树的.至于为什么不选择AVL作为底层实现呢?这是因为AVL是高度平衡的,导致我们每次对树的操作的复杂度比较高,相反的,红黑树可以在大概保持平衡特性的情况下,也能够实现较好的操作时间限制,所以综合来看,红黑树很显然是个更好的选择.

你可能感兴趣的:(理解红黑树)