二叉平衡树之红黑树

目录

1.概念

2.性质

3.节点的定义

4.插入

1.按照二叉搜索树规则插入结点

2.调整颜色

1.uncle存在且为红色

2.uncle不存在或者为黑    cur为

3.根节点改为黑色

5.验证

6.比较

7.应用


1.概念

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

2.性质

1.每个结点不是红色就是黑色

2.根节点是黑色

3.如果一个结点是红色,则他的两个孩子结点是黑色(没有两个相邻的红色结点)

4.每个结点,从该结点到其所有后代的叶子结点的路径中,含有的黑色节点个数相同

5.每个叶子结点都是黑色

为什么满足上面的性质,红黑树就能保证:其最长路径中节点个数不会超过最短路径节点个数的两倍?

最短:全黑,最长:红黑交替==>满足条件

3.节点的定义

static class RBTreeNode{
    public RBTreeNode left;
    public RBTreeNode right;
    public RBTreeNode parent;
    public int val;
    public COLOR color;

    public RBTreeNode(int val){
        this.val=val;
        //新增节点不能是黑色,要保证每条路上的黑色节点个数相同,会有问题:
        //1.要新增节点
        this.color=COLOR.RED;
    }

}

4.插入

1.按照二叉搜索树规则插入结点

1.创建结点

2.为空

3.遍历到当年结点为null

4.插入结点

 public boolean insert(int val){
        rbTreeNode node=new rbTreeNode(val);
        if(root==null){
            root=node;
            root.color=COLOR.BLACK;
            return true;
        }
        rbTreeNode parent=null;
        rbTreeNode cur=root;
        while(cur!=null){
            if(cur.val<val){
                parent=cur;
                cur=cur.right;
            }else if(cur.val==val){
                return false;
            }else{
                parent=cur;
                cur=cur.left;
            }
        }
        if(parent.val<val){
            parent.right=node;
           
        }else{
            parent.left=node;
        }
        node.parent=parent;
        cur=node;
    }

2.调整颜色

以parent == grand.left为例(cur,parent为红色),另一个刚好相反

g为黑色(可能为根节点,根节点为黑色),p为红色(两个连续的红色才需要调整),cur为红色(新插入的都是红色),以uncle的情况分类

1.uncle存在且为红色

p,u变为黑色 g变为红色 继续向上遍历

2.uncle不存在或者为黑    cur为

1.cur==parent.left -->右旋,p黑,g红

2.cur==parent.right -->左旋,cur和p交换,变为第一种

3.根节点改为黑色

 

情况1:cur为红,p为红,g为黑,u存在且为红

 把parent和uncle改为红色,grad改为黑色

思路: 不能有两个连着的红色结点,把p和u改为黑色,如果不把g改为红色就违背黑色节点个数相同的的性质

情况2:g为黑,u为黑,p为红,cur为红,cur为p的左孩子

情况3:g为黑,u为黑,p为红,cur为红,cur为p的右孩子

p做左单旋转,变成情况2

 public boolean insert(int val){
       RBTNode node=new RBTNode(val);
       if(root==null){
           root=node;
           root.color=COLOR.BLACK;
           return true;
       }

       RBTNode parent=null;
       RBTNode cur=root;
       while(cur!=null){
           if(cur.val<val){
               parent=cur;
               cur=cur.right;
           }else if(cur.val==val){
               return false;
           }else{
               parent=cur;
               cur=cur.left;
           }
       }
       if(parent.val<val){
           parent.right=node;
       }else{
           parent.left=node;
       }
       node.parent=parent;
       cur=node;


       //调整颜色
        while (parent!=null && parent.color==COLOR.RED){
            RBTNode grand=parent.parent;
            if(parent==grand.left){
                RBTNode uncle=grand.right;
                if(uncle!=null  && uncle.color==COLOR.RED){
                    //cur,p,u红,g黑
                    //方法:p.u黑,g,继续向上遍历
                    parent.color=COLOR.BLACK;
                    uncle.color=COLOR.BLACK;
                    grand.color=COLOR.RED;
                    cur=grand;
                    parent=cur.parent;
                }else{
                    if(cur==parent.right){
                        rotateLeft(parent);
                        RBTNode tmp=parent;
                        parent=cur;
                        cur=tmp;
                    }
                    rotateRight(grand);
                    parent.color=COLOR.BLACK;
                    grand.color=COLOR.RED;
                }
            }else{
                RBTNode uncle=grand.left;
                if(uncle!=null && uncle.color==COLOR.RED){
                    parent.color=COLOR.BLACK;
                    uncle.color=COLOR.BLACK;
                    grand.color=COLOR.RED;
                    cur=grand;
                    parent=cur.parent;
                }else{
                    if(cur==parent.left){
                        rotateRight(parent);
                        RBTNode tmp=parent;
                        parent=cur;
                        cur=tmp;
                    }
                    rotateLeft(grand);
                    grand.color=COLOR.RED;
                    parent.color=COLOR.BLACK;
                }
            }
        }
        root.color=COLOR.BLACK;
        return true;
    }

    private void rotateRight(RBTNode parent) {
        RBTNode subL=parent.left;
        RBTNode subLR=subL.right;
        subL.right=parent;
        parent.left=subLR;
        if(subLR!=null){
            subLR.parent=parent;
        }
        //记录原来的parent
        RBTNode pparent=parent.parent;
        parent.parent=subL;
        if(parent==root){
            root=subL;
            root.parent=null;
        }else{
            if(pparent.left==parent){
                pparent.left=subL;
            }else{
                pparent.right=subLR;
            }
            subL.parent=pparent;
        }
    }

    private void rotateLeft(RBTNode parent) {
        RBTNode subR=parent.right;
        RBTNode subRL=subR.left;
        subR.left=parent;
        parent.right=subRL;
        if(subRL!=null){
            subRL.parent=parent;
        }
        RBTNode pparent=parent.parent;
        parent.parent=subR;
        if(parent==root){
            subR=root;
            root.parent=null;
        }else{
            if(pparent.left==parent){
                pparent.left=subR;
            }else{
                pparent.right=subR;
            }
            subR.parent=pparent;
        }
    }

5.验证

红黑树的检测分为两步:

1. 检测其是否满足二叉搜索树(中序遍历是否为有序序列)

2.检测其是否满足红黑树的性质

1. 每个结点不是红色就是黑色

2. 根节点是黑色的

3. 如果一个节点是红色的,则它的两个孩子结点是黑色的【没有2个连续的红色节点】

4. 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均 包含相同数目的黑色结点

5. 每个叶子结点都是黑色的(此处的叶子结点指的是空结点)

public boolean isRBTree(){
        if(root==null){
            return true;
        }
        if(root.color!=COLOR.BLACK){
            System.out.println("违反了性质2:根节点必须是黑色的");
        }

        int blackNum=0;
        RBTNode cur=root;
        while(cur!=null){
            if(cur.color==COLOR.BLACK){
                blackNum++;
            }
            cur=cur.left;
        }
       //检查是否存在两个连续的红色节点  && 每条路径上黑色的节点的个数是一致的
        return checkRedColor(root) && checkBlackNum(root,0,blackNum);

    }

    private boolean checkBlackNum(RBTNode root, int pathBlackNum, int blackNum) {
        if(root==null) return true;
        if(root.color==COLOR.BLACK){
            pathBlackNum++;
        }
        if(root.left==null && root.right==null){
            if(pathBlackNum!=blackNum){
                System.out.println("违反了每条路径上的黑色节点的个数相同");
                return false;
            }
        }
        return checkBlackNum(root.left,pathBlackNum,blackNum)
                && checkBlackNum(root.right, pathBlackNum, blackNum);
    }

    private boolean checkRedColor(RBTNode root) {
        if(root==null) return true;
        if(root.color==COLOR.RED){
            RBTNode parent=root.parent;
            if(parent.color==COLOR.RED){
                System.out.println("违反了性质:连续出现两个红色的结点");
                return false;
            }
        }
        return checkRedColor(root.left)
                & checkRedColor(root.right);
    }
    public void inorder(RBTNode root){
        if(root==null){
            return ;
        }
        inorder(root.left);
        System.out.print(root.val+" ");
        inorder(root.right);
    }

6.比较

红黑树不追求绝对公平,只保证最长路径不超过最短路径的2倍,降低了插入和旋转的次数,在增删的结构中性能比AVL树更优

7.应用

java集合框架中的:TreeMap、TreeSet底层使用的就是红黑树

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2023年5月青少年机器人技术等级考试理论综合试卷(五级)

青少年机器人技术等级考试理论综合试卷&#xff08;五级&#xff09; 分数&#xff1a; 100 题数&#xff1a; 30 一、 单选题(共 20 题&#xff0c; 每题 4 分&#xff0c; 共 80 分) 1.ESP32 for Arduino&#xff0c; 下列程序的运行结果是&#xff1f; &#xff08; &#x…

浅谈无线测温系统在高压开关柜中的应用

关注acrelzxz&#xff0c;了解更多详情 摘要&#xff1a;高压开关柜是配电系统中重要的组成部分&#xff0c;其主要作用是控制电荷、分配电能和开断电流等&#xff0c;对维持系统的稳定性有一定的保障作用。将无线测温技术应用于高压开关柜&#xff0c;可以实现对其进行实时的…

校园外卖行业内卷之下,高校外卖创业者如何成为卷王?

伴随着外卖行业的不断发展&#xff0c;校园市场前景广阔。校园外卖市场因各大平台的竞争而变得越来越复杂。各种技术支持和经验参考让大学生创业校园外卖越来越困难&#xff0c;市场竞争也越来越激烈。 校园外卖市场究竟有多内卷&#xff1f; 外卖龙头企业。 校园市场广阔的发…

【高危】crypto-js<3.2.1 存在不安全的随机性漏洞

漏洞描述 crypto-js 是一个 JavaScript 加密库&#xff0c;用于在浏览器和 Node.js 环境中执行加密和解密操作。 crypto-js 3.2.1 之前版本中的 secureRandom 函数通过将字符串 0. 和三位随机整数拼接的格式生成加密字符串&#xff0c;攻击者可通过爆破破解加密字符。 漏洞…

Oracle 查询优化改写(第五章)

第五章 使用字符串 1.遍历字符串 SELECT 天天向上 内容&#xff0c;level&#xff0c;substr(天天向上, LEVEL, 1) 汉字拆分FROM Dual CONNECT BY LEVEL < Length(天天向上);2.计算字符在字符串中出现的次数 3.从字符中删除不需要的字符 若员工姓名有元音字母AEIOU&#x…

RPC远程调用

简介 PRC是一种调用方式而不是一种协议 在本地调用方式时由于方法在同一个内存空间&#xff0c;所以程序中可以直接调用该方法&#xff0c;但是浏览器端和服务端程序是不在一个内存空间的&#xff0c;需要使用网络来访问&#xff0c;就需要使用TCP或者UDP协议&#xff0c;由于…

STM32实现延时

在STM32单片机中&#xff0c;实现延时一般都是使用定时器&#xff0c;既可以使用Systick定时器&#xff0c;也可以使用常规的定时器。 定时器在设置了定时并开启之后&#xff0c;就会进入自主运行模式&#xff0c;其中&#xff0c;初始化设置这一阶段是由CPU执行相应指令完成的…

ubuntu双系统安装

1. 下载系统 国内镜像 http://mirrors.ustc.edu.cn/ubuntu-releases/2. U盘启动盘 Rufus 软件 制作U盘启动盘 Rufus 链接 https://rufus.en.softonic.com/3. 磁盘中准备一定未分配磁盘 我准备了100G 4. BIOS启动项选择为usb启动&#xff08;每个品牌进BIOS不同&#xff0…

Docker 进入容器和交换文件

1、进入容器 有些时候需要进入容器进行操作&#xff0c;使用 docker exec 命令&#xff0c;这个命令后面可以添加很多参数&#xff0c;我们这里只讲添加 -i 和 -it 参数。 只添加 -i 参数时&#xff0c;由于没有分配伪终端&#xff0c;界面没有我们熟悉的 Linux 命令提示…

Kubernetes 和 Prometheus

资源监控系统是容器编排系统必不可少的组件&#xff0c;也是服务治理的核心之一。而 Prometheus 本质上是一个开源的服务监控系统和时序数据库&#xff0c;是 CNCF 起家的第二个项目&#xff0c;目前已经成为 Kubernetes 生态圈中的监控系统的核心。 Prometheus 的核心组件 Pro…

java学习记录之MySql二

1 mysql回顾 1.1 DDL 数据定义语言&#xff1a;结构  数据库database create database 数据库名称 character set 字符集 [collate 比较]; drop database 数据库名称; alter database 数据库名称 character set 字符集 …;  表 create table 表名(字段描述 , … ); 字段描述…

GD32 SPI 查询方式和DMA方式在全双模式下效率区别

最近在使用SPI的时候&#xff0c;遇到了一些数据传输效率问题&#xff0c;在此记录自己学习过程。SPI的基础知识这里就不在讲述了&#xff0c;直接分析SPI查询方式和DMA方式的效率问题。这里使用的芯片是GD32F303CC。 SPI以查询方式进行全双工通信 1.查询手册&#xff0c;SPI…

Spring Cloud Alibaba-全链路灰度设计

文章目录 灰度发布概念灰度发布架构Spring Cloud Alibaba技术架构下的灰度发布实现基础设计HttpHeader设计 Spring Cloud Gateway改造Spring Cloud Gateway实现灰度发布过滤器 后端服务自定义Spring MVC请求拦截器OpenFeign改造自定义Loadbalancer 测试微服务注册元信息修改自定…

在windows11环境下安装CUDA11.6+Anaconda3+pyToach1.13搭建炼丹炉

0.电脑环境 系统&#xff1a;win11 显卡&#xff1a;NVIDIA GTX1650 还有一个pyCharm&#xff0c;其他也用不到了&#xff0c;需要的文章中会进行说明 1.安装CUDA11.6 目前2023.03出来的pyToach2.0是用不到了&#xff0c;因为最低版本支持CUDA11.7。我的显卡是1650&#xff0c…

阿里巴巴高管换血,吴永明接替张勇

文章目录 经济学人 &#x1f4b0; 第 26 周&#x1fa78; 阿里巴巴高管换血&#xff0c;吴永明接替张勇&#x1f304; 孙正义再出山&#x1f43f;️ 英特尔加码德国&#xff01;投资330亿美元建两座芯片工厂&#xff01;&#x1f30a; 亚马逊被指控强加 Prime 服务✈️ 印度航空…

Jmeter多接口测试之参数传递

目录 前言&#xff1a; 接口示例 正则表达式提取器 正则表达式提取实例 Json提取器 Json提取器实例 前言&#xff1a; 在进行多接口测试时&#xff0c;有些情况下需要将前一个接口返回数据作为后一个接口的参数&#xff0c;以模拟实际场景。JMeter作为一款常用的性能测试…

【EXCEL】如何查找特殊字符 问号‘?’星号 ‘*’

目录 0.环境 1.适用场景 1&#xff09;直接搜索问号的结果&#xff1a; 2&#xff09;修改【查找内容】后&#xff0c;搜索结果变为精准定位&#xff1a; 2.具体做法 0.环境 windows wps&#xff08;或excel&#xff0c;这里试了&#xff0c;此问题wps和excel表格是通用…

中间件解析漏洞

服务器解析漏洞算是历史比较悠久了&#xff0c;但如今依然广泛存在。在此记录汇总一些常见服务器&#xff08;WEB server&#xff09;的解析漏洞&#xff0c;比如IIS6.0、IIS7.5、apache、nginx等 2|0 二、IIS5.x-6.x解析漏洞&#xff08;针对asa/asp/cer&#xff09; 2|11、打…

区块链中怎么惩罚虚假信息的矿工,工作量证明POW,共识算法

目录 区块链中怎么惩罚虚假信息的矿工 工作量证明POW 什么是工作量证明&#xff1f; 现在出现了另一个问题&#xff1a;如果其他人偷看了小明的答案并且抢答了怎么办&#xff1f; 为什么区块可以安全广播&#xff1f; 共识算法 小结 区块链中怎么惩罚虚假信息的矿工 1…

三分钟学习一个python小知识4-----------我的对python中numpy的理解, 我列举了关于numpy常用的10个例子来深入理解numpy

这里写目录标题 1、NumPy是什么2、NumPy的常见应用---必须掌握2.1.创建一个数组2.2.数组的属性2.3.取数组中的元素2.4.数组的运算2.5.数组的转置2.6. 数组的索引和切片2.7. 数组的重塑2.8. 数组的广播2.9. 数组的聚合操作2.10. 数组的排序 总结 1、NumPy是什么 NumPy是专门用于…