数据结构与算法-红黑树

平衡二叉查找树

    平衡二叉树中任意一个节点的左右子树的高度相差不能大于1

        完全二叉树、满二叉树都是平衡二叉树,但非完全二叉树也有可能是平衡二叉树

    平衡二叉查找树满足上面平衡二叉树的定义,还满足二叉查找树的特点

    平衡二叉查找树为了解决普通二叉查找树频繁插入、删除等动态更新导致时间复杂度退化    

    平衡二叉查找树中“平衡”: 

        “平衡”可以等价为性能不退化

        让整棵树左右子树高度比较“平衡”,相应的插入、删除、查找等操作的效率高一些

    如设计一个平衡二叉查找树,只要树高度不比logn大很多,尽管不符合定义仍然可以算合格

数据结构与算法-红黑树_第1张图片
平衡二叉树 VS 非平衡二叉树

红黑树(Red-Black Tree)

    是一种不严格的平衡二叉查找树,属于最常用平衡二叉查找树

    满足红黑树前提条件

        所有节点只有黑色和红色

        根节点是黑色

        每个叶子节点都是黑色的空节点(NIL) (主要为了简化代码实现而设置)

            添加黑色的空叶子节点,可以在具体实现的时候公用一个空节点,不会太浪费空间

        任何相邻的节点都不能同时为红色

        每个节点从该节点到达其可达叶子节点的所有路径,都包含相同数目的黑色节点

    红黑树是“近似平衡”

        “平衡”可以等价为性能不退化,而“近似平衡”等价为性能不会退化的太严重

        二叉查找树操作的性能都跟树的高度成正比,极其平衡的二叉树高度大约为logn

    特点

        只要按照这些固定的调整规则来操作,就能将一个非平衡的红黑树调整成平衡

        左旋(rotate left): 围绕某个节点的左旋

        右旋(rotate right): 围绕某个节点的右旋

数据结构与算法-红黑树_第2张图片
左旋 VS 右旋

        红黑树的插入、删除操作会破坏红黑树的平衡,如何调整平衡

        名词介绍

            叔叔节点: 父节点的兄弟节点,

            祖父节点: 父节点的父节点

            关注节点: 正在处理的节点

            前驱节点: 中序遍历的序列中,当前节点上一个节点

            后继节点: 中序遍历的序列中,当前节点下一个节点

        插入操作的平衡调整

            红黑树定义: 插入的节点必须是红色,而且树中新插入的节点都放在叶子节点上

            具体情况如下:

                如果插入节点的父节点是黑色,那不需要任何调整,它仍然满足红黑树的定义

                如果插入的节点是根节点,那直接改变它的颜色,把它变成黑色就可以了

                其他情况都会违背红黑树的定义,需要进行两种基础的操作: 左右旋转和改变颜色

            实现过程

                红黑树的平衡调整过程是一个迭代的过程,

                关注节点随着不停地迭代处理,而不断发生变化。最开始的关注节点是新插入的节点

                新节点插入后,如果红黑树的平衡被打破,一般会有下面三种情况 & 如何实现再平衡

                Case 1.如果关注节点是a,它的叔叔节点d是红色,依次执行

                    将关注节点a的父节点b、叔叔节点d的颜色都设置成黑色

                    将关注节点a的祖父节点c的颜色设置成红色

                    关注节点变成a的祖父节点c

                    跳到CASE 2 或 CASE 3

数据结构与算法-红黑树_第3张图片
Case 1

                Case 2.如果关注节点是a,叔叔节点d是黑色,关注节点a是其父节点b的右子节点

                    关注节点变成节点a的父节点b;

                    围绕新的关注节点b左旋;

                    跳到 CASE 3

数据结构与算法-红黑树_第4张图片
Case 2

                Case 3.如果关注节点是a,叔叔节点d是黑色,关注节点a是其父节点b的左子节点

                    围绕关注节点a的祖父节点c右旋;

                    将关注节点a的父节点b、兄弟节点c的颜色互换。

数据结构与算法-红黑树_第5张图片
Case 3

        删除操作的平衡调整

            实现过程

                1.针对删除节点初步调整

                    红黑树定义中“只包含红色节点和黑色节点”,经过初步调整之后,

                    为了保证这一条要求,有些节点会被标记成两种颜色,“红-黑”或者“黑-黑”。

                    如果一个节点被标记为“黑-黑”,那在计算黑色节点个数的时候,要算成两个黑色节

                    如果一个节点既可以是红色,也可以是黑色,在下图用一半红色一半黑色来表示

                    如果一个节点是“红-黑”或者“黑-黑”,我会用左上⻆的一个小黑点来表示额外的黑色

                    Case 1:如果要删除的节点是a,它只有一个子节点b

                        删除节点a,并且把节点b替换到节点a的位置

                        节点a只能是黑色,节点b也只能是红色,不符合红黑树定义,把节点b改为黑色

数据结构与算法-红黑树_第6张图片
Case 1

                Case 2:如果要删除的节点a有两个非空子节点,且后继节点是节点a的右子节点c

                    如果节点a后继节点是右子节点c,把节点a删除且将节点c替换到节点a的位置

                    然后把节点c的颜色设置为跟节点a相同的颜色

                    如果节点c是黑色,给节点c右子节点d多加一个黑色,则节点d变成“红-黑”或“黑-黑”

                    这时关注节点变成了节点d,第二步的调整操作就会针对关注节点d来做

数据结构与算法-红黑树_第7张图片
Case 2

                    Case 3:如果要删除是节点a有两个非空子节点,且节点a后继节点不是右子节点

                        找到后继节点d,并将它删除,删除后继节点d的过程参照CASE 1

                        将节点a替换成后继节点d

                        把节点d的颜色设置为跟节点a相同的颜色

                        如果节点d是黑色,给节点d右子节c多加一个黑色,则节点c就成“红-黑”或“黑-黑”

                        这时关注节点变成节点c,第二步的调整操作就会针对关注节点c来做

数据结构与算法-红黑树_第8张图片
Case 3

                2.针对关注节点进行二次调整

                    经过初步调整之后,关注节点变成“红-黑”或“黑-黑”节点

                    二次调整是为了让红黑树中不存在相邻的红色节点

                    针对这个关注节点,我们再分四种情况来进行二次调整

                    Case 1: 如果关注节点是a,它的兄弟节点c是红色的

                        围绕关注节点a的父节点b左旋

                        关注节点a的父节点b和祖父节点c交换颜色

                        关注节点不变

                        继续从四种情况中选择适合的规则来调整

数据结构与算法-红黑树_第9张图片
Case 1

                    Case 2: 如果关注节点是a,兄弟节点c是黑色,且节点c左右子节点d、e都是黑色

                        将关注节点a的兄弟节点c的颜色变成红色

                        从关注节点a中去掉一个黑色,这个时候节点a就是单纯的红色或者黑色

                        给关注节点a的父节点b添加一个黑色,这时节点b就变成了“红-黑”或者“黑黑”

                        关注节点从a变成其父节点b

                        继续从四种情况中选择符合的规则来调整

数据结构与算法-红黑树_第10张图片
Case 2

                    Case 3: 如果关注节点是a,兄弟节点c是黑色,c左子节点d红色,c右子节点e黑色

                        围绕关注节点a的兄弟节点c右旋

                        节点c和节点d交换颜色

                        关注节点不变跳转到Case 4,继续调整

                    Case 4: 如果关注节点a的兄弟节点c是黑色的,并且c的右子节点是红色的

                        围绕关注节点a的父节点b左旋

                        将关注节点a的兄弟节点c的颜色,跟关注节点a的父节点b设置成相同的颜色;

                        将关注节点a的父节点b的颜色设置为黑色;

                        从关注节点a中去掉一个黑色,节点a就变成了单纯的红色或者黑色;

                        将关注节点a的叔叔节点e设置为黑色;

                        调整结束。

Case 4

    总结操作过程

        第一点,把红黑树的平衡调整的过程比作魔方复原,不要过于深究这个算法的正确性

            只要按照固定的操作步骤,保持插入、删除的过程,不破坏平衡树的定义即可

        第二点,找准关注节点,不要搞丢、搞错关注节点

            每种操作规则,都是基于关注节点来做的

            在迭代的调整过程中,关注节点在不停地改变

        第三点,插入操作的平衡调整比较简单,但是删除操作就比较复杂

            针对删除操作,我们有两次调整,

            第一次针对要删除的节点做初步调整,让调整后的红黑树继续满足第四条定义

                “每个节点到可达叶子节点的路径都包含相同个数的黑色节点”

                但是不满足第三条定义,有可能会存在两个红色节点相邻的情况

            第二次调整就是解决让红黑树不存在相邻的红色节点的问题

    几种平衡二叉查找树对比

        Treap(树堆)

            Treap是二叉搜索树和堆合并构成的数据结构,每个节点数据域包含2个值

                key值: 满足左子树<根节点<右子树 (满足二叉搜索树特性)

                weight值:小于等于(或大于等于)左右子节点 (满足堆特性)

            利用weight值作为随机因子来调整二叉树形状,所以在大部分情况下更平衡,性能更高

            但无法避免极端情况下时间复杂度的退化,不适用对于操作时间非常敏感场景

        Splay Tree(伸展树)

            是一种能够自我平衡的二叉查找树

            每次查找后对树进行调整,把被查找的条目搬移到离根节点近一些的地方

            它会沿着从某个节点到根节点之间的路径,通过一系列的旋转把这个节点搬移到根节点

            良好的的性能,同时存储所需的内存少

            但无法避免极端情况下时间复杂度的退化(特别在多线程环境)            

        AVL树

            一种高度平衡的二叉树,查找的效率非常高; 

            但是AVL树为了维持高度的平衡,每次插入、删除等操作都要调整,就比较复杂、耗时; 

            对于有频繁的插入、删除操作的数据集合,使用AVL树的代价就有点高

        红黑树

            红黑树的插入、删除、查找等操作性能都比较稳定

            因近似平衡,在维护平衡的成本上,要比AVL树要低

        综合对比

            为了支撑这种工业级的应用,我们更倾向于这种性能稳定的平衡二叉查找树

你可能感兴趣的:(数据结构与算法-红黑树)