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

红黑树

红黑树是一个相对的平衡,减少了旋转的消耗

  1. 一个节点不是红的就是黑的
  2. 根节点是黑的
  3. 一个节点是红的,孩子是黑的(没有连续的红色节点)
  4. 对于每个节点,从该节点到后代节点的简单路径,都包含相同的黑色(黑色节点的数量相等)
  5. 每个叶子节点都是黑色的(null节点)

最长路径不超过最短路劲的2倍
最短路径:全黑
最长路径: 一黑一红
假设每条路径黑节点是N,
n<=random path<=2n
路径要数到空位置
左右两边没那么均衡:整体的高度
假设红黑树中一中路径黑色节点=x
高度2x>=h>=x
全黑 一黑一红
2x-1<=N<=22x-1:N为节点个数

X>=logx(N),x<=log(N)/2

添加节点

添加节点主要是添加红色节点
以父亲为祖父的左节点为例

  1. 叔叔存在且为红色

    把父亲和叔叔都改成黑色
    把祖父改成红色

  2. 叔叔不存在或为黑色
    1. 我为父亲的左节点,进行一个右单旋,并把父亲改成黑色,把祖父改成红色
    2. 我为父亲的右节点,进行一个左右双旋,把我改黑,祖父改红

父亲为祖父的右节点与之相反

#pragma once
#include <iostream>
using namespace std;enum Color
{RED,BLACK
};
template <class K, class V>struct RBTreeNode
{RBTreeNode *_left;RBTreeNode *_right;RBTreeNode *_parent;pair<K, V> _kv;Color _col; //控制颜色RBTreeNode(const pair<K, V> &kv): _kv(kv), _left(nullptr), _right(nullptr), _parent(nullptr), _col(RED)//一开始的颜色给红色{}
};template <class K, class V>
class RBTree
{typedef RBTreeNode<K, V> Node;private:Node *_root;private:void _InOrder(Node *root){if (root == nullptr)return;_InOrder(root->_left);cout << root->_kv.first << " ";_InOrder(root->_right);}void RotateR(Node *parent){//右单旋转Node *subL = parent->_left;           //子节点Node *subLR = subL->_right;           //子节点的右节点Node *parentparent = parent->_parent; //出问题节点的父节点parent->_left = subLR;subL->_right = parent;parent->_parent = subL;if (subLR)subLR->_parent = parent;//和父节点的父节点连接if (parent == _root){//要旋转的节点已经是根//更新根_root = subL;_root->_parent = nullptr; //更新顶部}else{//父节点上面还有节点if (parentparent->_left == parent){//是左节点subL->_parent = parentparent;parentparent->_left = subL;}else{subL->_parent = parentparent;parentparent->_right = subL;}}}void RotateL(Node *parent) //左单旋{Node *subR = parent->_right;Node *subRL = subR->_left;Node *parentparent = parent->_parent;parent->_parent = subR;subR->_left = parent;parent->_right = subRL;if (subRL)subRL->_parent = parent;if (parent == _root){_root = subR;_root->_parent = nullptr;}else{if (parentparent->_right == parent){parentparent->_right = subR;subR->_parent = parentparent;}else{parentparent->_left = subR;subR->_parent = parentparent;}}}public:RBTree(): _root(nullptr){}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;}else{return false;}}//走到这里,就可以链接上cur = new Node(kv);cur->_col = RED; //新增节点颜色给红色cur->_parent = parent; //链接上父亲if (parent->_kv.first > kv.first){//比他小,在左边parent->_left = cur;}else{parent->_right = cur;}//插入之前一定是红黑树//这里就要控制平衡,通过颜色//插入黑节点(影响路径),还是红节点(只影响自己的,不影响其他区域)//往上调整//我为红,父亲如果为红,爷爷一定是黑色// 1.叔叔存在且为红while (parent && parent->_col == RED) //往上处理,父亲颜色为红色,就要处理,黑色就不要处理,为红,就不是根{Node *grandparent = parent->_parent;if (parent == grandparent->_left){Node *uncle = grandparent->_right; //叔叔就是在右边//叔叔存在且为红if (uncle && uncle->_col == RED){//叔叔存在,且为红//变色,继续向上处理parent->_col = BLACK;uncle->_col = BLACK;grandparent->_col = RED;cur = grandparent; //继续迭代往上操作parent = cur->_parent;}//叔叔不存在else //不存在,或存在且为黑{//不存在,进行旋转//旋转+变色if (cur == parent->_left){RotateR(grandparent); //进行右单旋转//变色parent->_col = BLACK;grandparent->_col = RED;}else{//双旋//左右双旋// p进行右单旋,g左单旋,g变红藕,cur变黑,RotateL(parent);RotateR(grandparent);cur->_col = BLACK;grandparent->_col = RED;}break;}}else //父亲是祖父的右边{Node *uncle = grandparent->_left; //叔叔就是在右边//叔叔存在且为红if (uncle && uncle->_col == RED){//叔叔存在,且为红//变色,继续向上处理parent->_col = BLACK;uncle->_col = BLACK;grandparent->_col = RED;cur = grandparent; //继续迭代往上操作parent = cur->_parent;}//叔叔不存在else //不存在,或存在且为黑{//不存在,进行旋转//旋转+变色if (cur == parent->_right){RotateL(grandparent); //进行右单旋转//变色parent->_col = BLACK;grandparent->_col = RED;}else{RotateR(parent);RotateL(grandparent);cur->_col = BLACK;grandparent->_col = RED;}break;}}}_root->_col = BLACK; //根的一定是黑色return true;}bool IsBalance(){if(_root&&_root->_col==RED){cout<<"根节点是黑色"<<endl;return false;}int basevalue=0;//基准值Node* left=_root;while(left){if(left->_col==BLACK){basevalue++;}left=left->_left;}//用最左路径黑色节点的数量,做基准值int blacknum=0;//每个节点的黑色个数return _IsBalance(_root,basevalue,blacknum);}void InOrder() //不能验证是不是AVL树{_InOrder(_root);}private:bool _IsBalance(Node* root,int basevalue,int blacknum){//根节点是黑的//红色,孩子是黑色,没有连续的红节点//每个路径含有相同的黑色if(root==nullptr){//一条路径走完了if(basevalue!=blacknum){//每条路劲都有blacknumcout<<"存在黑色节点数量不相等"<<endl;return false;}return true;}if(root->_col==RED&&root->_parent->_col==RED)//红节点{//检查它的父亲,一定有  cout<<"出现连续的红节点"<<endl;return false;}if(root->_col==BLACK){blacknum++;}return _IsBalance(root->_left,basevalue,blacknum)&&_IsBalance(root->_right,basevalue,blacknum);//没有用引用,下面的加加,不会影响下面}
};void test()
{RBTree<int, int> rbt;int a[]={16,3,7,11,9,26,18,14,15};// int a[] = {4,2,6,1,3,5,15,7,16,14};for (auto e : a){rbt.Insert(make_pair(e, e));}cout<<rbt.IsBalance()<<endl;rbt.InOrder();
}

相关文章:

红黑树

红黑树是一个相对的平衡&#xff0c;减少了旋转的消耗 一个节点不是红的就是黑的根节点是黑的一个节点是红的&#xff0c;孩子是黑的&#xff08;没有连续的红色节点&#xff09;对于每个节点&#xff0c;从该节点到后代节点的简单路径&#xff0c;都包含相同的黑色&#xff0…...

RIP路由协议的更新(电子科技大学TCP/IP第二次实验)

一&#xff0e;实验目的 1、掌握 RIP 协议在路由更新时的发送信息和发送方式 2、掌握 RIP 协议的路由更新算法 二&#xff0e;预备知识 1、静态路由选择和动态路由选择 2、内部网关协议和外部网关协议 3、距离向量路由选择 三&#xff0e;实验原理 RIP 协议&#xff08…...

基于JWT实现用户身份认证

常见场景 账号/密码登录、手机号验证码登录、微信扫码登录 解决方案 基于Session认证方案 什么是session认证方案 服务端生成httpsession认证(内存-sessionId)sessionId写到浏览器cookie浏览器请求的header中自动带sessionId到服务端服务端校验sessionId是否合法 优点 .…...

SaltStack 远程命令执行漏洞(CVE-2020-16846)

目录 (一)漏洞描述 (二)漏洞复现 1、在vulhub上启动docker 2、访问docker靶机 https /ip:8000...

SAP 详细解析成本收集器

成本收集器作为成本对象&#xff0c;主要应用于按期间进行成本核算的情况&#xff0c;在这种情况下会把产品创建为成本收集器&#xff0c;实际成本的收集和差异的结算全部按照成本收集器进行处理&#xff0c;财务的成本分析也针对成本收集器进行。 成本收集器是按期间核算&am…...

Vision Transformer学习了什么-WHAT DO VISION TRANSFORMERS LEARN? A VISUAL EXPLORATION

WHAT DO VISION TRANSFORMERS LEARN? A VISUAL EXPLORATION 文章地址 代码地址 摘要 视觉转换器( Vision Transformers&#xff0c;ViTs )正在迅速成为计算机视觉的事实上的架构&#xff0c;但我们对它们为什么工作和学习什么知之甚少。虽然现有研究对卷积神经网络的机制进…...

一种全新的图像滤波理论的实验(三)

一、前言 2023年02月22日&#xff0c;我发布了滤波后&#xff0c;为针对异常的白色和黑色像素进行处理的实验&#xff0c;本次发布基于上下文处理的方案的实验&#xff0c;目的是通过基于加权概率模型滤波后&#xff0c;在逆滤波时直接修复大量的白色和黑色的异常像素&#xf…...

CV——day79 读论文:基于小目标检测的扩展特征金字塔网络

Extended Feature Pyramid Network for Small Object DetectionI. INTRODUCTIONII. RELATED WORKA. 深层物体探测器B. 跨尺度特征C. 目标检测中的超分辨率III. OUR APPROACHA. 扩展特征金字塔网络B. 特征纹理传输C. 交叉分辨蒸馏IV. EXPERIMENTSA. Experimental Settings1&…...

智能家居项目(五)测试串口功能

目录 一、写一个单独测试串口的demo 二、直接运行上一篇智能家居的代码 一、写一个单独测试串口的demo 1、TTL串口与树莓派的连接方式 &#xff08;1&#xff09;TTL的RXD和TXD针脚连接到树莓的TXD和RXD上&#xff08;T–>R R–>T&#xff09;&#xff0c;交叉连&…...

2023年全国最新道路运输从业人员精选真题及答案7

百分百题库提供道路运输安全员考试试题、道路运输从业人员考试预测题、道路安全员考试真题、道路运输从业人员证考试题库等&#xff0c;提供在线做题刷题&#xff0c;在线模拟考试&#xff0c;助你考试轻松过关。 71.根据《中华人民共和国安全生产法》&#xff0c;生产经营单位…...

python的所有知识点(含讲解),不看就亏死了

目录 简介 特点 搭建开发环境 版本 hello world 注释 文件类型 变量 常量 数据类型 运算符和表达式 控制语句 数组相关 函数相关 字符串相关 文件处理 对象和类&#xff0c;注&#xff1a;不是那个对象&#xff01;&#xff01;&#xff01;&#xff01;&…...

【Servlet篇】Response对象详细解读

文章目录Response 继承体系Response 设置响应数据设置响应行数据设置响应头数据设置响应体数据Response 重定向Response 响应字符数据Response 响应字节数据Response 继承体系 前面说到&#xff0c;我们使用 Request 对象来获取请求数据&#xff0c;使用 Response 对象来设置响…...

SAP FICO期初开账存货导入尾差

一、问题 1.AFS物料网格级别库存导入先除再乘有尾差&#xff1a; 旧系统数据迁移自两个系统&#xff1a;一个管理数量账&#xff08;网格级别&#xff09;&#xff0c;一个管理金额账&#xff08;物料级别&#xff09; 2.MB52分工厂与MB5L分工厂统计差异&#xff1a; M…...

微信商城小程序怎么做_分享实体店做微信商城小程序制作步骤

各行各业都在用微商城小程序开店&#xff0c;不管是餐饮店还是便利店&#xff0c;还是五金店。都是可以利用微信小程序开一个线上店铺。实现线上跟线下店铺更加全面的结合。维护好自己的老客户。让您的客户给您拉新&#xff0c;带来新客户。小程序经过这几年的快速发展和不断升…...

【moment.js】时间格式化插件

Moment.js 用于在JavaScript中解析&#xff0c;验证&#xff0c;操作和显示日期和时间。是一款在项目中使用频率极高的时间格式化工具&#xff0c;Ant Design Vue 组件中就是使用它来处理时间的。 安装 npm install moment --save # npm yarn add moment # Ya…...

微信小程序开发【壹】

随手拍拍&#x1f481;‍♂️&#x1f4f7; 日期: 2023.02.24 地点: 杭州 介绍: 2023.02.24上午十点&#xff0c;路过学院的教学楼时&#x1f3e2;&#xff0c;突然看见了一团粉红色。走进一看是一排梅花&#x1f338;&#xff0c;赶在它们凋零前&#xff0c;将它们定格在我的相…...

2 k-近邻算法

0 问题引入 想一想&#xff1a;下面图片中有三种豆&#xff0c;其中三颗豆品种未知&#xff0c;如何判断他们类型&#xff1f; 1 KNN概述 1.1 KNN场景 电影可以按照题材分类&#xff0c;那么如何区分 动作片 和 爱情片 呢&#xff1f; 动作片&#xff1a;打斗次数更多爱情…...

深入探究文件I/O

目录Linux 系统如何管理文件静态文件与inode文件打开时的状态返回错误处理与errnostrerror 函数perror 函数exit、_exit、_Exit_exit()和_Exit()函数exit()函数空洞文件概念实验测试O_APPEND 和O_TRUNC 标志O_TRUNC 标志O_APPEND 标志多次打开同一个文件验证一些现象多次打开同…...

【LeetCode】剑指 Offer(9)

目录 题目&#xff1a;剑指 Offer 25. 合并两个排序的链表 - 力扣&#xff08;Leetcode&#xff09; 题目的接口&#xff1a; 解题思路&#xff1a; 代码&#xff1a; 过啦&#xff01;&#xff01;&#xff01; 题目&#xff1a;剑指 Offer 26. 树的子结构 - 力扣&#…...

python 遍历可迭代对象的方法

python 遍历可迭代对象的方法 可迭代(iterable) 迭代(遍历)就是按照某种顺序逐个访问对象中的每一项。 Python中有很多对象都是可以通过for语句来直接遍历的&#xff0c;例如list、string、dict等&#xff0c;这些对象都是可迭代的&#xff0c;被称为可迭代对象。 可以将可迭…...

【数据库】 第11章 并发控制

第11章 并发控制 事务 事务&#xff1a;(从微观角度&#xff0c;或者从DBMS角度)是数据库管理系统提供的控制数 据操作的一种手段&#xff0c;通过这一手段&#xff0c;应用程序员将一系列的数据库操作组合 在一起作为一个整体进行操作和控制&#xff0c;以便数据库管理系统能…...

Python3-数字

Python3 数字(Number) Python 数字数据类型用于存储数值。 数据类型是不允许改变的,这就意味着如果改变数字数据类型的值&#xff0c;将重新分配内存空间。 Python 支持三种不同的数值类型&#xff1a; 整型(int) - 通常被称为是整型或整数&#xff0c;是正或负整数&#x…...

(四十一)Read Committed隔离级别是如何基于ReadView机制实现的?

今天我们来给大家讲一下&#xff0c;基于之前我们说的ReadView机制是如何实现Read Committed隔离级别的&#xff0c;那么当然了&#xff0c;首先就是要先做一些简单的回顾。所谓的Read Committed隔离级别&#xff0c;我们可以用骚气一点的名字&#xff0c;就是简称为 RC 隔离级…...

React echarts封装

做大屏的时候经常会遇到 echarts 展示&#xff0c;下面展示在 React &#xff08;^18.2.0&#xff09; 中对 echarts &#xff08;^5.4.0&#xff09; 的简单封装。 文章首发于https://blog.fxss.work/react/echarts封装.html&#xff0c;样例查看 echarts 封装使用 props 说…...

【C语言进阶】了解计算机的程序环境和预处理过程 掌握计算机预处理操作

​ ​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;C语言进阶 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 文章目录1.编译与链接1.1 程…...

(三十六)大白话数据库幻读,本质到底是个什么问题?

上一讲我们给大家讲解了不可重复读这个问题&#xff0c;这个问题简单来说&#xff0c;就是一个事务多次查询一条数据&#xff0c;结果每次读到的值都不一样&#xff0c;这个过程中可能别的事务会修改这条数据的值&#xff0c;而且修改值之后事务都提交了&#xff0c;结果导致人…...

【算法经典题集】递归(持续更新~~~)

&#x1f63d;PREFACE&#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐ 评论&#x1f4dd;&#x1f4e2;系列专栏&#xff1a;算法经典题集&#x1f50a;本专栏涉及到的知识点或者题目是算法专栏的补充与应用&#x1f4aa;种一棵树最好是十年前其次是现在1.递归1.1 递归实现…...

多区域的OSPF实战配置

多区域的OSPF实战配置 需求 如图配置设备的接口IP地址如图规划OSPF网络的区域要求每个设备的 router-id 都是 x.x.x.x&#xff08;x是每个路由器的名字&#xff09;确保不同的PC之间可以互通 拓扑图 配置命令 PC1&#xff1a; 192.168.1.1 255.255.255.0 192.168.1.254PC2:…...

现在转行做程序员的多吗?

曾经有一名程序员说&#xff0c;他在编写程序时&#xff0c;就像一个发明家在做实验&#xff1b;当他把程序编好可以运行时&#xff0c;他就已经是个发明家了。 程序员作为众多转行人员首选的职业&#xff0c;也是被大众熟知了。但我们需要知道的不仅是它作为一个职业的定义&a…...

社招前端常见react面试题(必备)

解释 React 中 render() 的目的。 每个React组件强制要求必须有一个 render()。它返回一个 React 元素&#xff0c;是原生 DOM 组件的表示。如果需要渲染多个 HTML 元素&#xff0c;则必须将它们组合在一个封闭标记内&#xff0c;例如 <form>、<group>、<div&g…...