图解红黑树

news2024/9/21 12:42:47

gitee仓库:https://gitee.com/WangZihao64/data-structure-and-algorithm/tree/master/RBTree

目录

  • 概念
  • 红黑树的性质
  • 红黑树的调整规则

概念

红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出俩倍,因而是接近平衡的

红黑树的性质

  1. 每个结点不是红色就是黑色
  2. 根节点是黑色的
  3. 如果一个节点是红色的,则它的两个孩子结点是黑色的
  4. 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点
  5. 每个叶子结点都是黑色的(此处的叶子结点指的是空结点)

红黑树的调整规则

插入的顺序和avl树一样,根结点为黑色,插入新结点为红色,因为从该结点到后代结点都有相同数量的黑色结点,如果插入黑色,有很大的可能性会失败,所以插入红色结点是最为保险的做法,然后在依据规则进行调整,一般有3种情况

  • 情况一:cur为红,parent为红,grandfather为红,uncle存在且为红色
  • 解决方法:parent,uncle变黑,然后把grandfather给cur,继续向上调整

在这里插入图片描述

  • 情况二:cur为红,parent为红,grandfather为黑,uncle不存在||uncle存在且为黑色

  • 解决方法:parent为grandfather的左孩子,cur为parent的左孩子,对grandfather右旋

                        parent为grandfather的右孩子,cur为parent的右孩子,对grandfather左旋
    
                        **parent变黑,grandfather变红**
    

在这里插入图片描述

  • 情况三:cur为红,parent为红,grandfather为黑,uncle不存在||uncle存在且为黑色
  • 解决方法:parent为grandfather的左孩子,cur为parent的右孩子,对parent左旋,对grandfather右旋

parent为grandfather的右孩子,cur为parent的左孩子,对parent右旋,对grandfather左旋

cur变黑,grandfather变红

在这里插入图片描述

bool Insert(const pair<K,V>& kv)
    {
        if(_root== nullptr)
        {
            //根节点为黑色
            _root=new Node(kv);
            _root->_col=BLACK;
            return true;
        }
        Node* cur=_root;
        Node* parent=nullptr;
        while(cur)
        {
            if(cur->_kv.first>kv.first)
            {
                parent=cur;
                cur=cur->_left;
            }
            else if(cur->_kv.first<kv.first)
            {
                parent=cur;
                cur=cur->_right;
            }
                //遇到相同的值,返回false
            else
            {
                return false;
            }
        }
        cur=new Node(kv);
        if(kv.first>parent->_kv.first)
        {
            parent->_right=cur;
            cur->_parent=parent;
        }
        else
        {
            parent->_left=cur;
            cur->_parent=parent;
        }
        //parent不为空&&parent为红色需要进行调整
        while(parent&&parent->_col==RED)
        {
            Node* grandfather=parent->_parent;
            if(grandfather->_left==parent)
            {
                //情况一:cur为红,parent为红,uncle存在&&为红
                //把p,u变为black,g变为red
                Node* uncle=grandfather->_right;
                if(uncle&&uncle->_col==RED)
                {
                    parent->_col=BLACK;
                    uncle->_col=BLACK;
                    grandfather->_col=RED;
                    //把g变为cur继续向上调整
                    cur=grandfather;
                    parent=cur->_parent;
                }
                    //uncle不存在||uncle存在&&为黑色
                    //这两个可以直接break,因为无论是不是子树,root都是黑色
                else
                {
                    //情况二:parent->left=cur
                    //对grandfater右旋
                    //p变black,g变red
                    if(parent->_left==cur)
                    {
                        RotateR(grandfather);
                        parent->_col=BLACK;
                        grandfather->_col=RED;
                    }
                        //情况三:parent->right=cur
                        //先对cur左旋,在对grandfather右旋
                        //这是会变为情况二,cur变black,g变red
                    else
                    {
                        RotateL(parent);
                        RotateR(grandfather);
                        cur->_col = BLACK;
                        grandfather->_col = RED;
                    }
                    break;
                }
            }
                //grandfather->right=cur
                //和grandfather->left=cur类似
            else
            {
                //情况一:cur为红,parent为红,uncle存在&&为红
                //把p,u变为black,g变为red
                Node* uncle=grandfather->_left;
                if(uncle&&uncle->_col==RED)
                {
                    parent->_col=BLACK;
                    uncle->_col=BLACK;
                    grandfather->_col=RED;
                    //把g变为cur继续向上调整
                    cur=grandfather;
                    parent=cur->_parent;
                }
                    //uncle不存在||uncle存在&&为黑色
                    //这两个可以直接break,因为无论是不是子树,root都是黑色
                else
                {
                    //情况二:parent->right=cur
                    //对grandfater左旋
                    //p变black,g变red
                    //   g
                    //      p
                    //         c
                    if(parent->_right==cur)
                    {
                        RotateL(grandfather);
                        parent->_col=BLACK;
                        grandfather->_col=RED;
                    }
                        //情况三:parent->left=cur
                        //先对cur右旋,在对grandfather左旋
                        //这是会变为情况二,cur变black,g变red
                        //     g
                        //       p
                        //     c
                    else
                    {
                        RotateR(parent);
                        RotateL(grandfather);
                        cur->_col = BLACK;
                        grandfather->_col = RED;
                    }
                    break;
                }
            }
        }
        //根节点永远是黑色
        _root->_col=BLACK;
        return true;
    }
    void RotateL(Node* parent)
    {
        Node* subR=parent->_right;
        //右子树的左子树
        Node* subRL=subR->_left;
        //旋转的这棵树有可能是子树,所以需要保存parent的parent
        Node* pparent=parent->_parent;
        parent->_right=subRL;
        subR->_left=parent;
        //subLR可能不存在,需要单独判断
        if(subRL!= nullptr)
        {
            subRL->_parent = parent;
        }
        parent->_parent=subR;
        subR->_parent=pparent;
        //如果parent不是子树,就需要把_root给subR
        if(pparent== nullptr)
        {
            _root=subR;
        }
            //如果parent是子树的话,需要改变pparent的指向
        else if(pparent!= nullptr)
        {
            //子树是pparent的左子树/右子树,需要把pparent-left/->right指向subR
            if(pparent->_left==parent)
            {
                pparent->_left=subR;
            }
            else if(pparent->_right==parent)
            {
                pparent->_right=subR;
            }
        }
    }

    //右旋和左旋是一样的
    void RotateR(Node* parent)
    {
        Node* subL=parent->_left;
        Node* subLR=subL->_right;
        Node* pparent=parent->_parent;
        parent->_left=subLR;
        subL->_right=parent;
        if(subLR!= nullptr)
        {
            subLR->_parent=parent;
        }
        parent->_parent=subL;
        subL->_parent=pparent;
        if(pparent== nullptr)
        {
            _root=subL;
        }
        else if(pparent!= nullptr)
        {
            if(pparent->_left==parent)
            {
                pparent->_left=subL;
            }
            else if(pparent->_right==parent)
            {
                pparent->_right=subL;
            }
        }
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/697992.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Redis设计与实现笔记之字典

1.字典的实现 Redis中字典使用的哈希表结构 typedef struct dictht {// 哈希表数组dictEntry **table;// 哈希表大小unsigned long size;// 哈希表大小掩码&#xff0c;用于计算索引值// 总是等于 size - 1unsigned long sizemask;// 该哈希表已有节点的数量unsigned long use…

3D web可视化工具HOOPS Communicator与Autodesk的对比分析

越来越多的开发人员转向基于Web的2D和3D可视化和交互服务。这些使您只需使用网络浏览器即可快速向同事、客户或其他任何人展示设计。该领域的工具提供了大量功能&#xff0c;这些功能可能适合也可能不适合您的特定开发需求。 HOOPS Communicator的原始开发人员之一分享了对该市…

chatgpt赋能python:Python输出NaN的原因及解决方法

Python输出NaN的原因及解决方法 NaN&#xff08;Not a Number&#xff09;是一种特殊的数值类型&#xff0c;表示不是一个数字。在Python中&#xff0c;当某种计算结果无法表示为有限数字时&#xff0c;就会输出NaN。本文将介绍Python中输出NaN的原因&#xff0c;并提供一些解…

python: more Layer Architecture and its Implementation in Python

sql server: --学生表 DROP TABLE DuStudentList GO create table DuStudentList (StudentId INT IDENTITY(1,1) PRIMARY KEY,StudentName nvarchar(50),StudentNO varchar(50), --学号StudentBirthday datetime --学生生日 ) go mod…

Qt关闭主窗口后,退出所有异步线程

目录 1.要知道主窗口什么时候关闭2.关闭异步线程 1.要知道主窗口什么时候关闭 在widget.h新增下面的函数 private slots:void closeEvent(QCloseEvent *event);在widget.cpp新增 void Widget::closeEvent(QCloseEvent *event) {qDebug() << "关闭主窗口了&#x…

「网络编程」第三讲:认识协议及简单的协议定制

「前言」文章内容是关于协议的&#xff0c;大致内容是再次认识协议及简单协议的定制&#xff0c;目的是帮助理解协议&#xff0c;下面开始讲解&#xff01; 「归属专栏」网络编程 「笔者」枫叶先生(fy) 「座右铭」前行路上修真我 「枫叶先生有点文青病」「句子分享」 我与我周…

qt 调节win声音版本大小

QT4 情况下&#xff0c;运行的&#xff0c;会出错&#xff0c;目前暂时没有办法解决在&#xff0c;win下调节音量大小问题在这里插入代码片 参考资料 QT 对window系统下音量的设置和获取 还有个很好贴子&#xff0c;没有找到

LLM 应用参考架构:ArchGuard Co-mate 实践示例

随着&#xff0c;对于 LLM 应用于架构领域探索的进一步深入&#xff0c;以及 ArchGuard Co-mate 开发进入深入区&#xff0c;我们发现越来越多的通用模式。 在先前的文章里&#xff0c;我们总结了一系列的设计原则&#xff0c;在这篇文章里&#xff0c;我们将介绍 ArchGuard Co…

架构重构|性能和扩展性大幅提升的Share Creators智能数字资产管理软件3.0

作为数字资产管理行业的领军者&#xff0c;Share Creators智能数字资产管理软件持续致力于帮助企业和团队智能化管理数字资产&#xff0c;提升工业化管线制作效率。经过本次重构&#xff0c;Share Creators 3.0版本重装上阵&#xff0c;全面更新的服务架构标志着软件整体性能的…

C语言-数字爆炸游戏

问题&#xff1a; 你好&#xff0c;欢迎来到数字爆炸&#xff0c;系统随机生成一个数字&#xff0c;猜大了&#xff0c;提示猜大了&#xff0c;猜小了&#xff0c;提示猜小了。 思路&#xff1a; 先写游戏大概思路首先&#xff0c;会有菜单吧&#xff0c;所以先写一个菜单函数…

服务启动后能ping通但无法访问

近期业务需要&#xff0c;重启了服务器&#xff08;centos 7.4&#xff09;&#xff0c;但是各类服务启动后&#xff0c;仍然无法访问&#xff0c;Nginx的白页面都访问不到&#xff0c;能ping通&#xff0c;nslookup 域名解析也没问题&#xff0c;考虑是防火墙 -- 查看防火墙启…

《2023 信创软件品牌影响力报告》发布!融云入选「信创生态」代表厂商

信创正由试点实践转向全面推广。关注【融云 RongCloud】&#xff0c;了解协同办公平台更多干货。 由于外围环境收紧和国内数字经济高速发展等原因&#xff0c;信创产业在顶层战略的指引推动下蓬勃发展&#xff0c;相关政策有力促进了芯片、操作系统、数据库、办公软件、工业软…

jquery html页面先加载内容过几秒后显示数据

&#x1f607;作者介绍&#xff1a;一个有梦想、有理想、有目标的&#xff0c;且渴望能够学有所成的追梦人。 &#x1f386;学习格言&#xff1a;不读书的人,思想就会停止。——狄德罗 ⛪️个人主页&#xff1a;进入博主主页 &#x1f5fc;推荐专栏&#xff1a;点击进入查看 &a…

文心一言 VS 讯飞星火 VS chatgpt (50)-- 算法导论6.2 2题

二、参考过程 MAX-HEAPIFY&#xff0c;写出能够维护相应最小堆的 MIN-HEAPIFY(A&#xff0c;i)的伪代码&#xff0c;并比较 MIN-HEAPIFY 与 MAX-HEAPIFY 的运行时间。 文心一言&#xff1a; MIN-HEAPIFY(A, i)的伪代码如下&#xff1a; 1.将节点i及其子树中的最小元素交换到…

linux定时清理三个月前的应用日志

目录 思路find 命令需要用到 -mtime n 参数 shell脚本三种方法方法一方法二方法三 配置计划任务 思路 要想删除三个月前的日志&#xff0c;先得找到三个月前的日志才行&#xff0c;可以通过 find命令查找。 find 命令 1.find命令基本介绍     find顾名思义就是查找&…

UMS攸信入选福建省知识产权优势企业名单,为企业自主创新体系建设增添新动能!

近日&#xff0c;根据福建省市场监管局办公室《关于组织开展2023年度省知识产权优势企业申报及复核工作的通知》&#xff08;闽市监办〔2023〕11号&#xff09;要求&#xff0c;将拟确认的2023年福建省知识产权优势企业名单予以公示。 攸信技术成功入选该名单&#xff0c;荣获2…

chatgpt赋能python:Python退出主程序:如何正确结束你的Python代码

Python退出主程序&#xff1a;如何正确结束你的Python代码 对于Python编程的初学者来说&#xff0c;经常会遇到一个问题&#xff1a;如何正确退出Python程序&#xff1f;在Python中&#xff0c;有许多种方式可以停止运行Python程序&#xff0c;但不是所有的方法都是相同的。如…

vue 访问本地json数据

如果你的项目中需要模拟下json数据&#xff0c;来看下访问速度&#xff0c;那就参照这个试试吧&#xff0c;首先创建test.josn&#xff0c;放在pulic目录下&#xff0c;见下图 定义js // 文件 prodOrder.jsexport function test(data) {return request({url: http://localhost…

无缝数据转换!使用C++ 实现 Excel文件与CSV之间的相互转换

CSV格式是一种通用的文本文件格式&#xff0c;可在多个应用程序之间共享和使用。相比之下&#xff0c;Excel文件是一种电子表格格式&#xff0c;通常只能在Microsoft Excel中编辑和查看。因此&#xff0c;将Excel文件转换为CSV格式可使数据更方便地在其他应用程序中使用&#x…

Linux服务器丢包故障的解决思路及引申的TCP/IP协议栈理论

Linux服务器丢包故障的解决思路及引申的TCP/IP协议栈理论 我们使用Linux作为服务器操作系统时&#xff0c;为了达到高并发处理能力&#xff0c;充分利用机器性能&#xff0c;经常会进行一些内核参数的调整优化&#xff0c;但不合理的调整常常也会引起意想不到的其他问题&#x…