数据结构~基础2~树【《二叉树、二叉搜索树、AVL树、B树、红黑树》的设计】~红黑树

简介: 数据结构~基础2~树【《二叉树、二叉搜索树、AVL树、B树、红黑树》的设计】~红黑树

数据结构~基础2~树【《二叉树、二叉搜索树、AVL树、B树、红黑树》的设计】~红黑树


 

一、 红黑树


9.png

红黑树之介绍:

-----------形态上是特殊的二叉搜索树【特殊体现在颜色上,同时在逻辑上它是等价于4阶B树的】

❀ 红黑树是怎么等价于4 阶B 树的?---------红黑树要变成B树:需要将红结点和黑结点进行合并(黑色作为根【也是中间元素】)

红黑-->B 树: 结点有四种情况是:①红-黑-红、②红-黑、③黑-红、④黑

 

 

 

❀ 红黑树的通用接口:二叉搜索树的通用接口 + 增加之后、删掉之后

旋转【左旋、右旋】、旋转之后的处理【更新父结点的关系】(旋转、旋转之后跟AVL 树一样)

 

 

■ 插入的所有位置情况:


10.png


■ 增加之后:

❀ 总结红黑树的添加之后的调整 ❀ :

1,分类:(具体过程需要根据父结点作为左结点、右结点进行对称)

(1)不需要调整:

  ■ 当前结点是根,染黑即可;

  ■ 父结点是黑,不用处理。

(2)需要调整:(根据叔父结点是否为红色进行划分)

  ■ case1:叔父是红色,当前结点x 可左可右,染黑 父、叔,染红爷,回溯到结点爷处。

  ■ case2:叔父是黑色,当前结点x 是右孩子【红红是LR型】,先进行左旋,转化成case3;

(先考虑当前结点是右孩子,因为它处理一下就变成了case3)【小细节,当前结点x 指向 父结点时,旋转x(其实旋转的是原先的父结点的位置)】;

  ■ case3:叔父是黑色,当前结点x 是左孩子【红红是LL型】,染黑父,染红爷,然后右旋。


@Override
    protected void afterAdd(Node<E> node) {
        // 判断父结点
        Node<E> parent = node.parent;
        // 添加的是根【当添加第一个结点时】/ 或者上溢到了根结点时
        if (parent == null) {
            black(node);
            return;
        }
        // 若父结点是黑色时,不用处理,直接返回
        if (isBlack(parent))
            return;
        // 若叔父结点是红色的[B 树的上溢]
        Node<E> uncle = parent.sibling();
        Node<E> grand = red(parent.parent);
        if (isRed(uncle)) {
            // 染黑爸爸、叔叔,把祖父染成红色,相当于新插入的结点
            black(uncle);
            black(parent);
            // ① 上溢时,也要染红祖父结点
            afterAdd(grand);
            return;
        }
        // 观察一下,对代码进行优化,共同拥有的抽到外部之类的
        // 来到这里叔父不是红色
        if (parent.isLeftChild()) { // L
            // ② 旋转时,也要 染红结点
            if (node.isLeftChild()) { // LL
                // 染黑父结点,染红祖父结点
                black(parent);
                // 右旋
            } else { // LR
                // 染红自己、染黑祖父结点
                black(node);
                // 左旋后右旋
                rotateLeft(parent);
            }
            rotateRight(grand);
        } else { // R
            // ② 旋转时,也要 染红结点
            if (node.isLeftChild()) { // RL
                // 染红自己、染黑祖父结点
                black(node);
                // 左旋后右旋
                rotateRight(parent);
            } else { // RR
                // 染黑父结点,染红祖父结点
                black(parent);
                // 左旋
            }
            rotateLeft(grand);
        }
    }


■ 删除的所有位置情况:


11.png


■ 删除之后:

❀ 总结红黑树的删除之后的调整 ❀ :

1,删除结点是红色,(完美),不用处理;

2,删除结点是黑色:【看替代结点--前驱/后驱结点】

(1)替代结点是红色,染黑替代结点【前驱/后驱结点】

(2)替代结点是黑色,(若是根,完美,不用处理),黑色结点

 

● 黑色叶子结点:【看兄弟】:----- 站在B树角度,发生了下溢

【B树中的处理,找兄弟借,兄弟借不了,找父结点下来合并】

[1] 兄弟是黑色,且能借(至少有一个子红色结点),旋转借出去。

【直接借的话,不符合二叉搜索树的特点,根大于左子树,根小于右子树(需要旋转交换一下结点,(符合二叉搜索树特点)然后再借)】。

[2] 兄弟是黑色,不能借(没有红色结点),看父结点:

① 父结点是红色:染黑父结点,染红兄弟,进行合并。

② 父结点是黑色,下溢处理。

[3] 兄弟是红色,通过旋转,把侄子(黑色结点)变成兄弟【又变成了删除的结点的兄弟结点是黑色结点】

 

 

 

 

● 黑色叶子结点:【看兄弟】:

[3] 兄弟是红色,通过旋转,把侄子(黑色结点)变成兄弟【又变成了删除的结点的兄弟结点是黑色结点】:

只能是图示:(兄弟跟父结点在同一个B树的子结点上(同一层上),且红色兄弟有两个黑色的子结点)


12.png


删除黑色叶子结点时,发生了下溢,而显然不在同一层上的兄弟肯定是不能借出结点,

只能考虑跟自己处于同一层【兄弟的儿子】,向兄弟的儿子进行借。【但是在B树中借的前提,两者是兄弟关系】

所以目标就是要将兄弟的儿子,变成我的兄弟才能顺利成章的借。

 

[2] 兄弟是黑色,不能借(没有红色结点),看父结点:

① 父结点是红色:染黑父结点,染红兄弟,进行合并。


13.png

14.png


[2] 兄弟是黑色,不能借(没有红色结点),看父结点:

② 父结点是黑色,下溢处理。

 15.png


[1] 兄弟是黑色,且能借(至少有一个子红色结点),旋转借出去。【旋转的结果是变成了根(成为独立的B树结点),就需要将其染黑】



16.png


protected void afterRemove2(Node<E> node, Node<E> replacement) {
        //删除结点是红色 或者 替代结点【前驱/后驱】是红色
        if(isRed(node))    return;
        if (isRed(replacement)) {
            black(replacement);
            return;
        }
        //接下来考虑删除结点是黑色【排除掉根的情况】
        Node<E> parent = node.parent;
        // 删除的是根节点
        if (parent == null)
            return;
        // 删除黑色叶子节点【下溢】
        boolean left = parent.left == null || node.isLeftChild();// 判断被删除的node是左还是右
        Node<E> sibling = left ? parent.right : parent.left;
        if (left) { // 被删除的节点在左边,兄弟节点在右边
            //看兄弟【兄弟是红色,染黑兄弟,通过左旋,让兄弟成为根,更新一下兄弟位置】
            if (isRed(sibling)) { // 兄弟节点是红色
                black(sibling);
                red(parent);
                rotateLeft(parent);
                // 重新指一下兄弟(更新一下兄弟位置)
                sibling = parent.right;
            }
            // 【兄弟结点是黑色,兄弟没有红色子结点,不能借】~下溢情况
            if (isBlack(sibling.left) && isBlack(sibling.right)) {
                // 兄弟节点借不出,父节点要向下跟兄弟节点合并【父结点作为下来结点的根】
                boolean parentBlack = isBlack(parent);
                black(parent);
                red(sibling);
                if (parentBlack) {//若是父结点原先是黑色,导致塌陷,递归
                    afterRemove2(parent, null);
                }
            // 【兄弟结点是黑色,兄弟有红色子结点可以借】    
            } else { 
                // 兄弟节点的左结点是黑色,兄弟要先旋转
                if (isBlack(sibling.right)) {
                    rotateRight(sibling);
                    //更新一下兄弟结点
                    sibling = parent.right;
                }
                //旋转之后,旋转之后的中心节点继承 parent 的颜色;
                //旋转之后的左右节点染为 BLACK ----【成为独立的B树结点】
                color(sibling, colorOf(parent));
                black(sibling.right);
                black(parent);
                rotateLeft(parent);
            }
        } else { // 被删除的节点在右边,兄弟节点在左边
            if (isRed(sibling)) { // 兄弟节点是红色
                black(sibling);
                red(parent);
                rotateRight(parent);
                // 更换兄弟
                sibling = parent.left;
            }
            // 兄弟节点必然是黑色
            if (isBlack(sibling.left) && isBlack(sibling.right)) {
                // 兄弟节点没有1个红色子节点,父节点要向下跟兄弟节点合并
                boolean parentBlack = isBlack(parent);
                black(parent);
                red(sibling);
                if (parentBlack) {
                    afterRemove2(parent,null);
                }
            } else { // 兄弟节点至少有1个红色子节点,向兄弟节点借元素
                // 兄弟节点的左边是黑色,兄弟要先旋转
                if (isBlack(sibling.left)) {
                    rotateLeft(sibling);
                    sibling = parent.left;
                }
                color(sibling, colorOf(parent));
                black(sibling.left);
                black(parent);
                rotateRight(parent);
            }
        }
    }



目录
相关文章
|
4月前
|
存储 监控 安全
企业上网监控系统中红黑树数据结构的 Python 算法实现与应用研究
企业上网监控系统需高效处理海量数据,传统数据结构存在性能瓶颈。红黑树通过自平衡机制,确保查找、插入、删除操作的时间复杂度稳定在 O(log n),适用于网络记录存储、设备信息维护及安全事件排序等场景。本文分析红黑树的理论基础、应用场景及 Python 实现,并探讨其在企业监控系统中的实践价值,提升系统性能与稳定性。
138 1
|
8月前
|
存储 算法 Java
算法系列之数据结构-二叉树
树是一种重要的非线性数据结构,广泛应用于各种算法和应用中。本文介绍了树的基本概念、常见类型(如二叉树、满二叉树、完全二叉树、平衡二叉树、B树等)及其在Java中的实现。通过递归方法实现了二叉树的前序、中序、后序和层次遍历,并展示了具体的代码示例和运行结果。掌握树结构有助于提高编程能力,优化算法设计。
257 10
 算法系列之数据结构-二叉树
|
8月前
|
算法 Java
算法系列之数据结构-Huffman树
Huffman树(哈夫曼树)又称最优二叉树,是一种带权路径长度最短的二叉树,常用于信息传输、数据压缩等方面。它的构造基于字符出现的频率,通过将频率较低的字符组合在一起,最终形成一棵树。在Huffman树中,每个叶节点代表一个字符,而每个字符的编码则是从根节点到叶节点的路径所对应的二进制序列。
208 3
 算法系列之数据结构-Huffman树
|
8月前
|
存储 自然语言处理 数据库
【数据结构进阶】AVL树深度剖析 + 实现(附源码)
在深入探讨了AVL树的原理和实现后,我们不难发现,这种数据结构不仅优雅地解决了传统二叉搜索树可能面临的性能退化问题,还通过其独特的平衡机制,确保了在任何情况下都能提供稳定且高效的查找、插入和删除操作。
640 19
|
8月前
|
算法 Java
算法系列之数据结构-二叉搜索树
二叉查找树(Binary Search Tree,简称BST)是一种常用的数据结构,它能够高效地进行查找、插入和删除操作。二叉查找树的特点是,对于树中的每个节点,其左子树中的所有节点都小于该节点,而右子树中的所有节点都大于该节点。
311 22
|
8月前
|
数据库 C++
【数据结构进阶】红黑树超详解 + 实现(附源码)
本文深入探讨了红黑树的实现原理与特性。红黑树是一种自平衡二叉搜索树,通过节点着色(红/黑)和特定规则,确保树的高度接近平衡,从而实现高效的插入、删除和查找操作。相比AVL树,红黑树允许一定程度的不平衡,减少了旋转调整次数,提升了动态操作性能。文章详细解析了红黑树的性质、插入时的平衡调整(变色与旋转)、查找逻辑以及合法性检查,并提供了完整的C++代码实现。红黑树在操作系统和数据库中广泛应用,其设计兼顾效率与复杂性的平衡。
1501 3
|
8月前
|
C语言 C++ 容器
【数据结构】二叉搜索树(二叉排序树)
本文介绍了二叉搜索树(Binary Search Tree, BST)的定义、实现及其性能分析。二叉搜索树是一种特殊的二叉树,其特点是左子树所有节点值小于根节点值,右子树所有节点值大于根节点值,且每个子树也满足此特性。文中详细讲解了BST的节点结构、插入、查找、删除等操作的实现,并通过C++代码展示了这些功能。此外,还讨论了BST的性能:在理想情况下,时间复杂度接近O(logN),但在最坏情况下可能退化为O(N)。为了提高效率,后续将学习自平衡二叉搜索树如AVL树和红黑树。掌握BST有助于理解STL中的set和map容器。感谢阅读,欢迎点赞支持。
679 9
|
10月前
|
存储 C++
【C++数据结构——树】哈夫曼树(头歌实践教学平台习题) 【合集】
【数据结构——树】哈夫曼树(头歌实践教学平台习题)【合集】目录 任务描述 相关知识 测试说明 我的通关代码: 测试结果:任务描述 本关任务:编写一个程序构建哈夫曼树和生成哈夫曼编码。 相关知识 为了完成本关任务,你需要掌握: 1.如何构建哈夫曼树, 2.如何生成哈夫曼编码。 测试说明 平台会对你编写的代码进行测试: 测试输入: 1192677541518462450242195190181174157138124123 (用户分别输入所列单词的频度) 预
332 14
【C++数据结构——树】哈夫曼树(头歌实践教学平台习题) 【合集】
|
10月前
|
Java C++
【C++数据结构——树】二叉树的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现二叉树的基本运算。​ 相关知识 创建二叉树 销毁二叉树 查找结点 求二叉树的高度 输出二叉树 //二叉树节点结构体定义 structTreeNode{ intval; TreeNode*left; TreeNode*right; TreeNode(intx):val(x),left(NULL),right(NULL){} }; 创建二叉树 //创建二叉树函数(简单示例,手动构建) TreeNode*create
279 12
|
10月前
|
C++
【C++数据结构——树】二叉树的性质(头歌实践教学平台习题)【合集】
本文档介绍了如何根据二叉树的括号表示串创建二叉树,并计算其结点个数、叶子结点个数、某结点的层次和二叉树的宽度。主要内容包括: 1. **定义二叉树节点结构体**:定义了包含节点值、左子节点指针和右子节点指针的结构体。 2. **实现构建二叉树的函数**:通过解析括号表示串,递归地构建二叉树的各个节点及其子树。 3. **使用示例**:展示了如何调用 `buildTree` 函数构建二叉树并进行简单验证。 4. **计算二叉树属性**: - 计算二叉树节点个数。 - 计算二叉树叶子节点个数。 - 计算某节点的层次。 - 计算二叉树的宽度。 最后,提供了测试说明及通关代
189 10

热门文章

最新文章