当前位置: 首页 > news >正文

红黑树介绍及插入操作的实现

🎉个人名片:

🐼作者简介:一名乐于分享在学习道路上收获的大二在校生
🙈个人主页🎉:GOTXX
🐼个人WeChat:ILXOXVJE
🐼本文由GOTXX原创,首发CSDN🎉🎉🎉
🐵系列专栏:零基础学习C语言----- 数据结构的学习之路----C++的学习之路
🐓每日一句:如果没有特别幸运,那就请特别努力!🎉🎉🎉
————————————————

文章目录

  • 1.红黑树的概念
  • 2 红黑树的性质
  • 3 红黑树节点的定义
  • 4.红黑树的插入操作(分类详解)
  • 5.红黑树与AVL树的比较

1.红黑树的概念

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

在这里插入图片描述

2 红黑树的性质

性质:

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

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

首先,要满足黑色节点数目相同,则当只有黑色节点的时候,路径最短,因为红色节点不能连续出现,所以当黑色节点与红色节点交替的时候,路径最长,并且为最短的两倍。

3 红黑树节点的定义

enum color                      //颜色
{RED,BLACK
};
template<class K, class V>
struct AVLNode
{AVLNode<K, V>* _left;AVLNode<K, V>* _right;AVLNode<K, V>* _parent;pair<K, V> _kv;color _col;                 //记录节点颜色AVLNode(pair<K, V>& kv)      :_left(nullptr), _right(nullptr), _parent(nullptr), _kv(kv), _col(RED)           //新节点的颜色默认为红色{}
};

新插入节点的颜色为红色的原因?

原因:因为红黑树有一条规则,就是每条路径的黑色节点数目相等,插入前每条路径的黑色数目是相等的,但是如果插入的是黑色节点的话,那么该条路径的黑色节点的数目就多了一个,直接违反规则,所以插入新节点为红色节点;

4.红黑树的插入操作(分类详解)

红黑树是在二叉搜索树的基础上加上其平衡限制条件,因此红黑树的插入可分为两步:

  1. 按照二叉搜索的树规则插入新节点
  2. 检测新节点插入后,红黑树的性质是否造到破坏
    因为新节点的默认颜色是红色,因此:如果其双亲节点的颜色是黑色,没有违反红黑树任何性质,则不需要调整;
    但当新插入节点的双亲节点颜色为红色时,就违反了性质三不能有连在一起的红色节点,此时需要对红黑树分情况来讨论:

含义解析:
cur为当前节点,p为父节点,g为祖父节点,u为叔叔节点
在这里插入图片描述
情况一:cur为红色,p为红色,g为黑色,u存在并且为红色

根据上图进行分析:
在这里插入图片描述
解析:
这里p与cur都为红色,违反规则,我们不能直接将p的颜色改为黑色,如果直接改为黑色的话,则每条路径的黑色节点数目就变化了,违反规则。

我们应该将p与u变为红色,g变为黑色,如果g是子树,还需向上调整(比如上图中的下面一种情况),如果g是根节点,则需要变回黑色,因为规则里根节点必须为黑色;

代码实现

    //这里是一个while循环,只展示了循环体里面的代码//情况一:uncle存在并且为红色if (uncle && uncle->_col == RED){uncle->_col = BLACK;parent->_col = BLACK;grandfather->_col = RED;parent = grandfather;          //如果为子树,则继续向上调整cur = parent; if (_root == grandfather)      //如果g为根节点,则改回黑色{grandfather->_col = BLACK;}}

情况二:u不存在或则u存在并且为黑色
下面的分类与AVL树的旋转的分类很类似;

分析一u不存在/存在且黑色并且p为g的左,c为p的左 或则 p为g的右,c为p的右(p,g,c在一条线上)

当u不存在时:处理方法:单旋+变色
在这里插入图片描述
当u存在时:处理方法:也是单旋+变色
在这里插入图片描述

在这里插入图片描述
总结:

当u存在为黑色或则不存在时,都需要旋转+变色(这里的旋转与上章AVL旋转一样)
如果c为p的左,并且p为g的左,则右旋
如果c为p的右,并且p为g的右,则左旋
变色: 都是p变成黑色,g变为红色

代码实现

//p为g左,c为p左
if (parent==grandfather->_left && cur==parent->_left)
{ rotateR(grandfather);parent->_col = BLACK;grandfather->_col = RED;
}
//p为g右,c为p右
else if (parent == grandfather->_right && cur == parent->_right)
{rotateL(grandfather);parent->_col = BLACK;grandfather->_col = RED;
}

分析三:u不存在或则存在为黑色,但是p为g的左,c为p的右边 或则 p为g的右,c为p的左(p,g,c不在一条线上)

当u不存在时:处理方法:双旋+变色
在这里插入图片描述
当u存在时:处理方法:双旋+变色
在这里插入图片描述

总结:
当g,p,c不在一条街直线上时,需要双旋+变色处理
旋转方向的判定和AVL树的旋转一样;(上章讲过)

代码实现:

//一左一右
else if(parent == grandfather->_left && cur == parent->_right)
{rotateL(parent);rotateR(grandfather);cur->_col = BLACK;parent->_col = BLACK;break;
}
else if (parent == grandfather->_right && cur == parent->_left)
{rotateR(parent);rotateL(grandfather);cur->_col = BLACK;parent->_col = BLACK;break;
}

插入总代码

bool insert(pair<K, V>& kv)
{if (_root == nullptr){_root = new Node(kv);_root->_col = BLACK;}//找插入点Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_kv > kv){parent = cur;cur = cur->_left;}else if (cur->_kv < kv){parent = cur;cur = cur->_right;}else{return false;}}//插入if (cur == parent->left){cur = new Node(kv);parent->_left = cur;cur->_parent = parent;}else if (cur == parent->right){cur = new Node(kv);parent->_right = cur;cur->_parent = parent;}//调节颜色/调节使其满足规则while (parent && parent->_col == RED){Node* grandfather = parent->_parent;if (parent = grandfather->_left){Node* uncle = grandfather->_right;}else{Node* uncle = grandfather->_left;}//情况一:uncle存在并且为红色if (uncle && uncle->_col == RED){uncle->_col = BLACK;parent->_col = BLACK;grandfather->_col = RED;parent = grandfather;          //如果为子树,则继续向上调整cur = parent; if (_root == grandfather)      //如果g为根节点,则改回黑色{grandfather->_col = BLACK;}}//uncle不存在或则存在为黑色else{//p为g左,c为p左if (parent==grandfather->_left && cur==parent->_left){ rotateR(grandfather);parent->_col = BLACK;grandfather->_col = RED;break;}//p为g右,c为p右else if (parent == grandfather->_right && cur == parent->_right){rotateL(grandfather);parent->_col = BLACK;grandfather->_col = RED;break;}//一左一右else if(parent == grandfather->_left && cur == parent->_right){rotateL(parent);rotateR(grandfather);cur->_col = BLACK;parent->_col = BLACK;break;}else if (parent == grandfather->_right && cur == parent->_left){rotateR(parent);rotateL(grandfather);cur->_col = BLACK;parent->_col = BLACK;break;}}}
}
//左单旋
void rotateL(Node* parent)
{Node* pparent = parent->_parent;     //记录所旋转根节点的父亲Node* pNodeR = parent->_right;Node* pNodeRL = pNodeR->_left;if (pNodeRL)                         //如果该旋转节点的右节点的左孩子存在parent->_right = pNodeRL;pNodeR->_left = parent;//新的父节点的链接if (parent == _root){_root = pNodeR;pparent = nullptr;}else{if (pparent->_left == parent){pparent->_left = pNodeR;}else{pparent->_right = pNodeR;}}
}
//右单旋
void rotateR(Node* parent)
{Node* pparent = parent->_parent;Node* pNodeL = parent->_left;Node* pNodeLR = pNodeL->_right;if (pNodeLR)parent->_left = pNodeLR;pNodeL->_right = parent;if (parent == _root){_root = pNodeL;pparent = nullptr;}else{if (pparent->_left == parent){pparent->_left = pNodeL;}else{pparent->_right = pNodeL;}}
}

5.红黑树与AVL树的比较

红黑树和AVL树都是高效的平衡二叉树,增删改查的时间复杂度都是O( l o g 2 N log_2 N log2N),红黑树不追求绝对平衡,其只需保证最长路径不超过最短路径的2倍,相对而言,降低了插入和旋转的次数,所以在经常进行增删的结构中性能比AVL树更优,而且红黑树实现比较简单,所以实际运用中红黑树更多。

相关文章:

红黑树介绍及插入操作的实现

&#x1f389;个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名乐于分享在学习道路上收获的大二在校生 &#x1f648;个人主页&#x1f389;&#xff1a;GOTXX &#x1f43c;个人WeChat&#xff1a;ILXOXVJE &#x1f43c;本文由GOTXX原创&#xff0c;首发CSDN&…...

[linux初阶][vim-gcc-gdb] TwoCharter: gcc编译器

目录 一.Linux中gcc编译器的下载与安装 二.使用gcc编译器来翻译 C语言程序 ①.编写C语言代码 ②翻译C语言代码 a.预处理 b.编译 c.汇编 d.链接 ③.执行Main 二进制可执行程序(.exe文件) 三.总结 一.Linux中gcc编译器的下载与安装 使用yum命令(相当于手机上的应用…...

单例设计模式(2)

单例设计模式&#xff08;2&#xff09; 单例模式存在的问题 单例对 OOP 特性的支持不友好 oop的特性&#xff1a;封装、继承、多态、抽象&#xff1b;以Id生成器代码为例&#xff0c;如果未来某一天&#xff0c;我们希望针对不同的业务采用不同的 ID 生成算法。比如&#x…...

boost::asio 启用 io_uring(Linux 5.10)队列支持

欲启用 boost::asio 对于 io_uring 的支持&#xff0c;这需要以下几个先决条件&#xff1b; 1、boost 1.78 及以上发行版本 Revision History - 1.78.0 (boost.org) 2、Linux kernel 5.10 及以上发行版本 3、在预定义头文件&#xff08;stdafx.h&#xff09;、或编译器预定义…...

Android 自定义坐标曲线图(二)

Android 自定义坐标曲线图_android 自定义曲线图-CSDN博客 继上一篇文章&#xff0c;点击折线图上的点&#xff0c;显示提示信息进行修改&#xff0c;之前通过回调&#xff0c;调用外部方法&#xff0c;使用popupwindow或dialog来显示&#xff0c;但是这种方法对于弹框显示的位…...

每日OJ题_子序列dp⑧_力扣446. 等差数列划分 II - 子序列

目录 力扣446. 等差数列划分 II - 子序列 解析代码 力扣446. 等差数列划分 II - 子序列 446. 等差数列划分 II - 子序列 难度 困难 给你一个整数数组 nums &#xff0c;返回 nums 中所有 等差子序列 的数目。 如果一个序列中 至少有三个元素 &#xff0c;并且任意两个相邻…...

GOPROXY 代理设置

通常报错&#xff1a; 1.http: server gave HTTP response to HTTPS client 2.timeout 解决指令&#xff1a;(会话临时性)&#xff0c;长久的可以在配置文件中配置 go env -w GOPROXYhttps://goproxy.cn,direct 长久的&#xff0c;在~/.bashrc文件中添加&#xff1a; expo…...

Redis面经

Redis面经 Redis缓存穿透、缓存击穿和缓存雪崩及解决方案概述缓存穿透详解及解决方案缓存击穿详解及解决方案缓存雪崩详解及解决方案 Redis持久化机制什么是数据持久化&#xff1f;Redis数据持久化概述RDB持久化的优缺点AOF持久化混合持久化 Redis缓存穿透、缓存击穿和缓存雪崩…...

【c++】类和对象(六)深入了解隐式类型转换

&#x1f525;个人主页&#xff1a;Quitecoder &#x1f525;专栏&#xff1a;c笔记仓 朋友们大家好&#xff0c;本篇文章我们来到初始化列表&#xff0c;隐式类型转换以及explicit的内容 目录 1.初始化列表1.1构造函数体赋值1.2初始化列表1.2.1隐式类型转换与复制初始化 1.3e…...

什么是nginx正向代理和反向代理?

什么是代理&#xff1f; 代理(Proxy), 简单理解就是自己做不了的事情或实现不了的功能&#xff0c;委托别人去做。 什么是正向代理&#xff1f; 在nginx中&#xff0c;正向代理指委托者是客户端&#xff0c;即被代理的对象是客户端 在这幅图中&#xff0c;由于左边内网中…...

【Go】面向萌新的Gin框架知识梳理学习笔记

目录 Gin框架简介 路由&路由组 1. 定义基本路由 2. 参数传递 3. 查询字符串参数 4. 路由组 5. 路由中间件 模板渲染 1. 加载模板 2. 定义模板 3. 渲染模板 4. 自定义模板函数 返回json 1. 导入 Gin 包 2. 创建 Gin 引擎 3. 定义路由和处理器函数 4. 运行服…...

baseDao增删改查.

这里写目录标题 1、baseDao增删改查介绍2、basDao类3、BasDao类的作用 1、baseDao增删改查介绍 (1)、增加Create&#xff09;操作&#xff1a; 通过BaseDao的insert方法可以向数据库中插入一条新的记录。 该方法接受一个实体对象作参数&#xff0c;将该对象的属性映射到表的字…...

什么是面向对象【大白话Java面试题】

什么是面向对象 同样是解决一个问题&#xff0c;面向对象的角度是将问题抽象成对象的形式。通过分类的思维方式&#xff0c;将问题分成几个解决方案的对象。给每个对象赋值属性和方法&#xff0c;对每个对象的细节进行面向过程的思维&#xff0c;执行自己的方法来解决问题。 …...

PyTorch 教程-快速上手指南

文章目录 PyTorch Quickstart1.处理数据2.创建模型3.优化模型参数4.保存模型5.加载模型 PyTorch 基础入门1.Tensors1.1初始化张量1.2张量的属性1.3张量运算1.3.1张量的索引和切片1.3.2张量的连接1.3.3算术运算1.3.4单元素张量转变为Python数值 1.4Tensor与NumPy的桥接1.4.1Tens…...

【有芯职说】数字芯片BES工程师

一、 数字芯片BES工程师简介 今天来聊聊数字芯片BES工程师&#xff0c;其中BES是Back End Support的缩写&#xff0c;就是后端支持的意思。其实这个岗位是数字IC前端设计和数字IC后端设计之间的一座桥&#xff0c;完成从寄存器传输级设计到具体工艺的mapping和实现。这个岗位在…...

暴力破解pdf文档密码

首先安装pdfcrack工具包 apt install pdfcrack 默认密码字典存储在/usr/share/wordlists里&#xff0c;是gz文件&#xff0c;将它解压并copy到pdf目录 然后使用pdfcrack破解 密码在最后一行user-password的单引号里...

蓝桥杯刷题第四天

思路&#xff1a; 这道题很容易即可发现就是简单的暴力即可完成题目&#xff0c;我们只需满足所有数的和为偶数即可保证有满足条件的分法&#xff0c;同时也不需要存下每个输入的数据&#xff0c;只需要知道他是偶数还是奇数即可&#xff0c;因为我们只需要偶数个奇数搭配在一块…...

03-数据库的用户管理

一、创建新用户 mysql> create user xjzw10.0.0.% identified by 1; Query OK, 0 rows affected (0.01 sec) 二、查看当前数据库正在登录的用户 mysql> select user(); ---------------- | user() | ---------------- | rootlocalhost | ---------------- 1 row …...

每日一题 --- 三数之和[力扣][Go]

三数之和 题目&#xff1a;15. 三数之和 给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] nums[k] 0 。请 你返回所有和为 0 且不重复的三元组。 **注意&#x…...

vue render 函数详解 (配参数详解)

vue render 函数详解 (配参数详解) 在 Vue 3 中&#xff0c;render 函数被用来代替 Vue 2 中的模板语法。 它接收一个 h 函数&#xff08;或者是 createElement 函数的别名&#xff09;&#xff0c;并且返回一个虚拟 DOM。 render 函数的语法结构如下&#xff1a; render(h) …...

ubuntu23.10配置RUST开发环境

系统版本: gcc版本 下载rustup安装脚本: curl --proto =https --tlsv1.2 https://sh.rustup.rs -sSf | sh下载完成后会自动执行 选择默认安装选项 添加cargo安装目录到环境变量 vim ~/.bashrc<...

Vue性能优化--gZip

一、gZip简单介绍 1.1 什么是gzip gzip是GNUzip的缩写&#xff0c;最早用于UNIX系统的文件压缩。HTTP协议上的gzip编码是一种用来改进web应用程序性能的技术&#xff0c;web服务器和客户端&#xff08;浏览器&#xff09;必须共同支持gzip。目前主流的浏览器&#xff0c;Chro…...

蓝桥杯第七届大学B组详解

目录 1.煤球数量&#xff1b; 2.生日蜡烛&#xff1b; 3.凑算式 4.方格填数 5.四平方和 6.交换瓶子 7.最大比例 1.煤球数量 题目解析&#xff1a;可以根据题目的意思&#xff0c;找到规律。 1 *- 1个 2 *** 3个 3 ****** 6个 4 ********** 10个 不难发现 第…...

荣誉 | 人大金仓连续三年入选“金融信创优秀解决方案”

3月28日&#xff0c;由中国人民银行领导&#xff0c;中国金融电子化集团有限公司牵头组建的金融信创生态实验室发布“第三期金融信创优秀解决方案”&#xff0c;人大金仓新一代手机银行系统解决方案成功入选&#xff0c;这也是人大金仓金融行业解决方案连续第三年获得用户认可。…...

【关于jupyter notebook】一打开就闪退的问题

在Anaconda Prompt中输入jupyter notebook发现是有个错误。 里面多了一个__init__.py的文件导致报错。删除之后&#xff0c;就可以使用了...

若依 3.8.7版本springboot前后端分离 整合mabatis plus

1.去掉mybatis 这一步我没有操作&#xff0c;看别人的博客有说不去掉可能冲突&#xff0c;也可能不冲突&#xff0c;我试下来就没去掉如需要去除&#xff0c;到总的pom.xml中properties标签下的<mybatis-spring-boot.version>x.x.x</mybatis-spring-boot.version>…...

vue做移动端自适应插件实现rem

1.实现方式 postcss-pxtorem&#xff1a;将px转换为rem amfe-flexible&#xff1a;为html、body提那家font-size&#xff0c;窗口调整的时候重新设置font-size 2.安装与使用 npm install amfe-flexible --save npm install postcss-pxtorem --save-dev 1.再main.js入口文件…...

android 快速实现 图片获取并裁剪(更换头像)

1.获取图片框架&#xff1a;https://github.com/LuckSiege/PictureSelector 2.图片裁剪框架&#xff1a;https://github.com/jdamcd/android-crop 3.Glide图片加载框架&#xff1a;https://github.com/bumptech/glide 2.build.gradle依赖&#xff1a; dependencies {// Pic…...

垃圾回收机制--GC 垃圾收集器--JVM调优-面试题

1.触发垃圾回收的条件 新生代 Eden区域满了&#xff0c;触发young gc (ygc)老年代区域满了&#xff0c;触发full gc (fgc)通过ygc后进入老年代的平均大小大于老年代的可用内存,触发full gc(fgc).程序中主动调用的System.gc()强制执行gc,是full gc&#xff0c;但是不必然执行。…...

Java基础知识总结(29)

Java虚拟机 运行时数据区 程序计数器 方法区&#xff1a;Java 8以后没有方法区&#xff0c;改为了元空间&#xff08;MetaSpace&#xff09; 虚拟机栈 堆 本地方法栈 程序计数器 它可以看作是当前线程所执行的字节码的行号指示器。在Java虚拟机的概念模型里&#xff0c…...

广西网站/2022真实新闻作文400字

前些天&#xff0c;测试人员向我反映有一家企业的通讯录同步接口不返回数据&#xff0c;我查日志nginx的相应access.log状态码是499&#xff0c;请求超时&#xff0c;从网上查找资料分析有两种可能&#xff1a;1.客户端主动断开连接2.服务端响应超时造成客户端连接中断问了客户…...

网站建设布吉/安年软文网

文章目录 引言I 实现显示隐藏按钮II 控制按钮是否可响应事件see also引言 应用场景:登录界面、密码修改界面 效果: I 实现显示隐藏按钮 声明显示隐藏按钮 @property (weak...

宣传册样式/无锡网站建设方案优化

LaTex说起LaTex&#xff0c;又会扯出Tex、MikTeX、CJK等一系列东西。这并不是我们关注的重点&#xff0c;然而如果你有时间&#xff0c;可以当个睡前故事看看这篇文章。我们只需要知道:LaTex有一套自成体系的语法&#xff0c;常用于科研生产、试卷等文档排版。支持复杂公式&…...

wordpress配置七牛云cdn/手机百度账号登录个人中心

近来通过Appium&#xff0c;Robotium等几个框架去了解移动平台自动化测试。Appium官方实例是使用ContactManager.apk&#xff0c;而Robotium使用的是SDK自带的Notepad.apk&#xff0c;为了方便比较&#xff0c;在了解Appium的同时把实例修改成跟Robotium一致的Notepad.apk并记录…...

wordpress当前文章tags/自动的网站设计制作

危言 对金融危机最普遍的官方解释是次贷问题&#xff0c;然而次贷总共不过几千亿&#xff0c;而美国政府救市资金早已到了万亿以上&#xff0c;为什么危机还是看不到头&#xff1f;有文章指出危机的根源是 金融机构采用“杠杆”交易&#xff1b;另一些专家指出金融危机的背后是…...

宜春做网站 黑酷seo/市场营销推广策划方案

cuda历史各个版本下载链接 https://developer.nvidia.com/cuda-toolkit-archive 1、下载deb包 按照指令要求下载 注意&#xff1a; sudo dpkg -i cuda-repo-ubuntu1604-10-0-local-10.0.130-410.48_1.0-1_amd64.deb sudo apt-key add /var/cuda-repo-/7fa2af80.pub (这步需注意…...