红黑树的理解与实现(详解)

相关的数据结构:

搜索二叉树-CSDN博客

AVL树的创建与检测-CSDN博客

个人主页:敲上瘾-CSDN博客

个人专栏:游戏、数据结构、c语言基础、c++学习、算法

目录

一、红黑树规则:

二、红黑树的插入

1.变色

2.单旋+变色

3.双旋+变色

三、红黑树的验证

四、源码:


一、红黑树规则:

红黑树规则(重点!):

  • 每个结点不是红⾊就是⿊⾊。
  • 根结点是⿊⾊的。
  • 如果⼀个结点是红⾊的,则它的两个孩⼦结点必须是⿊⾊的,也就是说任意⼀条路径不会有连续的红⾊结点。
  • 对于任意⼀个结点,从该结点到其所有NULL结点的简单路径上,均包含相同数量的⿊⾊结点。
     

        红黑树的性质都由以上4点规则决定的,其中的一个性质:红黑树最长路径的节点数量一定不会大于最短路径的两倍。这使得红黑树虽然不是完全平衡但高度差没有那么大,查找效率依旧是longN级别的。

        红黑树为什么能实现最长路径不会超过最短路径的两倍呢?我们可以想一想如果其中任意一条路径有n个黑节点,最短路径的颜色是如何分布,最长路径颜色又是如何分布的呢?其实很简单根据第4条规则我们可以最短的路径的节点不可能低于n个,(即最少的时候为n个黑节点)。又由第3条规则可以知道最长的路径的节点数不可能超过2n个,(即最多的时候为n个黑节点,n个红节点)。

        所以我们要实现一个红黑树只需要维护以上4条规则即可。

二、红黑树的插入

        因为红黑树也是一棵二叉搜索树,所以我们先按二叉搜索树的逻辑将节点进行插入,需要注意插入的是红色节点,因为黑色节点维护起来非常的困难。

(1)如果该新节点的父亲为黑节点,不用再做调整,直接返回。

(2)如果不是则需要分情况进行更新:

        在这里我们是因为父亲为红节点才进行更新的,因为在插入之前已经保证这是一棵红黑树,又因为父亲为红色,所以爷爷一定为黑色。

        而我们要做的就是把新节点的父亲更新成黑色,如何更新如何分情况呢关键就在于叔叔是否存在以及叔叔的颜色。接下来就以父亲为爷爷的左孩子为例进行讲解,父亲为爷爷的右孩子同理。

说明:下图中假设我们把新增结点标识为c(cur),c的⽗亲标识为p(parent),p的⽗亲标识为
g(grandfather),p的兄弟标识为u(uncle)。

1.变色

 叔叔u存在且为红:

        该情况比较简单,因为要保持每条路径的黑节点的个数相同,所以直接将g的黑色分配给p和u,而g变为红色即可。如上图:

        但是有个问题g的父亲是完全有可能是红节点的,照这样的话又出现了两个连续的红色节点,所以再以g作为新的c节点,g的父亲作为新的p节点,然后更新g,最后循环进行调整就可以解决。

如下x是通过变色更新上来的节点:

2.单旋+变色

 叔叔u不存在或为黑:

        当叔叔u不存在或为黑,我们发现无论如何变色都是无法调整得当的,所以这就需要旋转+变色操作了。

该情况又可以细分为两种情况:

  • c和p在g的同一侧,需要单旋+变色
  • c和p在g的不同侧,需要双旋+变色

首先来分析第一种情况:

如下:以g为旋转点进行右旋,然后将p更新为黑色,c和g为红色。

关于旋转请参考:AVL树的创建与检测-CSDN博客 

3.双旋+变色

 叔叔u不存在或为黑并且c和p在g的不同侧我们进行双旋+变色,如下:

注意:因为考虑要使根节点为黑色,防止在调整过程将根节点改为黑色,所以在每次调整过后直接将根节点更新为黑色。

三、红黑树的验证

        红黑树的验证并不用去验证高度差,也不用去验证最长路径的节点数是不是小于最短路径的两倍,因为即使这一些条件都满足也不一定是红黑树,想要验证红黑树只需要验证是否满足红黑树的规则即可,只要满足了那些规则,那么红黑树的性质自然就有了。

  • 规则1就不用验证因为这是必然的
  • 规则2也是比较简单一个if语句就解决。
  • 规则3的验证:遍历整棵树,当遍历到红色节点时判断它的父亲是否为黑色,不是则违反规则。
  • 规则4的验证:任意选择一条路径(如一直往左走)并记录其中的黑节点数目(记为count),然后遍历整棵树的所有路径并记录黑节点数目,然后在路径结束后与count比较,如果不相等则违反规则。

四、源码:

#pragma once
#include<iostream>
using namespace std;
enum Color{red, black};
template<class T>
struct RBNode
{RBNode(T key):data(key),color(red),left(nullptr),right(nullptr),prev(nullptr){}T data;enum Color color;RBNode<T>* left;RBNode<T>* right;RBNode<T>* prev;
};
template<class T>
class RBTree
{
public:typedef RBNode<T> Node;RBTree():root(nullptr){}bool insert(T data){Node* newNode = new Node(data);if (root == nullptr){root = newNode;root->color = black;return true;}Node* cur = root;Node* parent = root;while (cur){parent = cur;if (newNode->data.first <= cur->data.first)cur = cur->left;else cur = cur->right;}if (newNode->data.first <= parent->data.first)parent->left = newNode;else parent->right = newNode;newNode->prev = parent;//需要调整cur = newNode;Node* grandfather = parent->prev;Node* uncle = nullptr;while (parent&&parent->color == red){grandfather = parent->prev;if (parent == grandfather->left){uncle = grandfather->right;if (uncle && uncle->color == red){grandfather->color = red;parent->color = uncle->color = black;cur = grandfather;parent = cur->prev;}else{if (cur == parent->left){ReverseR(grandfather);parent->color = black;grandfather->color = red;}else{ReverseL(parent);ReverseR(grandfather);cur->color = black;parent->color = grandfather->color = red;}}}else{uncle = grandfather->left;if (uncle && uncle->color == red){grandfather->color = red;parent->color = uncle->color = black;cur = grandfather;parent = cur->prev;}else{if (cur == parent->right){ReverseL(grandfather);parent->color = black;grandfather->color = red;}else{ReverseR(parent);ReverseL(grandfather);cur->color = black;parent->color = grandfather->color = red;}}}}root->color = black;return true;}void ReverseR(Node* parent){Node* subL = parent->left;Node* subLR = subL->right;parent->left=subLR;subL->right = parent;//Node* pparent = parent->prev;subL->prev = pparent;if (pparent == nullptr) root = subL;else{if (pparent->left == parent) pparent->left = subL;else pparent->right = subL;}if (subLR) subLR->prev = parent;parent->prev = subL;}void ReverseL(Node* parent){Node* subR = parent->right;Node* subRL = subR->left;parent->right = subRL;subR->left = parent;//Node* pparent = parent->prev;subR->prev = pparent;if (pparent == nullptr) root = subR;else{if (pparent->left == parent) pparent->left = subR;else pparent->right = subR;}if (subRL) subRL->prev = parent;parent->prev = subR;}bool IsBalanceTree(){if (root == nullptr) return true;if (root->color == red) return false;int count = 0;Node* cur = root;while (cur){if (cur->color == black) count++;cur = cur->left;}return Check(root, 0, count);}bool Check(Node* root,int path,const int refNum){if (root == nullptr) return path == refNum;if (root->color == red && root->prev->color == red) return false;if (root->color == black) path++;return Check(root->left, path, refNum) && Check(root->right, path, refNum);}
private:Node* root;
};

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

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

相关文章

WebGoat SQL Injection (intro) 源码分析

首先了解 java 中 mysql 的连接&#xff1a;java连接Mysql WebGoat SQL Injection (intro) 10 根据提示&#xff1a;下面两个输入框只有一个受到 sql 注入攻击。题目要求是检索到所有数据 发现请求路径为 SqlInjection/assignment5b 定位到所在文件如下&#xff0c;根据代码…

电影评论网站开发:Spring Boot技术详解

摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了电影评论网站的开发全过程。通过分析电影评论网站管理的不足&#xff0c;创建了一个计算机管理电影评论网站的方案。文章介绍了电影评论网站的系统分析部分&…

【uniapp】使用Promise封装request

目录 1、创建config目录 2、创建settings.js 3、创建目录utils 4、创建request.js 5、创建api目录 6、创建apis.js文件 7、业务系统调用 7.1 业务系统banner 7.2 业务系统荣誉页面&#xff08;传参&#xff09; 前言&#xff1a;使用Promise封装request 1、创建config…

Python实现火柴人的设计与实现

1.引言 火柴人&#xff08;Stick Figure&#xff09;是一种极简风格的图形&#xff0c;通常由简单的线段和圆圈组成&#xff0c;却能生动地表达人物的姿态和动作。火柴人不仅广泛应用于动画、漫画和涂鸦中&#xff0c;还可以作为图形学、人工智能等领域的教学和研究工具。本文…

前端学习---(1)HTML

一个后端狗, 在公司悄摸得学习前端技术 在公司上班时间看视频影响不太好 按照这个来吧: https://gitee.com/chinese-gitee/Web 前端基础要学: HTML, CSS,JS 浏览器 浏览器中最重要的是渲染引擎(浏览器内核),JS引擎(常见的V8引擎) 渲染引擎: 用来解析 HTML与CSS。渲染引擎决定了…

UNIX网络编程-传输层

概述 传输层主要包括&#xff1a;TCP、UDP、SCTP&#xff08;流控制传输协议&#xff09;&#xff01; 绝大多数客户端/服务器网络应用都使用TCP/UDP。SCTP是一个较新的协议&#xff0c;最初设计用于跨因特网传输电话信令。 这些传输协议都转而使用网络协议IP&#xff1a;或是…

2023年华为杯数学建模竞赛题F论文和代码

强对流降水临近预报建模与优化 对问题一&#xff0c;为了实现基于前一小时&#xff08;10帧&#xff09;的实测雷达观测量&#xff08;ZH、ZDR、KDP&#xff09;&#xff0c;对后续一小时&#xff08;10帧&#xff09;的ZH进行预报&#xff0c;本文首先建立了线性拟合与RMSE双驱…

matlab相位图

% 清空工作空间和命令窗口 clear; clc; % 模拟生成时间t&#xff0c;位移y(t)和角位移theta(t) t linspace(0, 100, 1000); % 时间从0到100&#xff0c;包含1000个点 y 1e-5 * sin(2 * pi * 0.1 * t) .* exp(-0.01 * t); % 位移y(t) 振荡衰减 theta 1e-6 * cos(2 * pi * …

第11章 索引(postgresql v17)

V17 Chapter 11. Indexes 索引是增强数据库性能的常用方法。索引允许数据库服务器查找和检索特定的行&#xff0c;比没有索引要快得多。但是索引也会给整个数据库系统增加开销&#xff0c;因此应该合理使用索引。 1、介绍 假设我们有一个类似这样的表: CREATE TABLE test1 …

验证archive_command配置是否正确

要验证 archive_command 配置是否正确&#xff0c;你可以按照以下步骤进行&#xff1a; ‌检查配置文件‌&#xff1a; 确保 postgresql.conf&#xff08;或你的 PostgreSQL 实例使用的任何自定义配置文件&#xff09;中的 archive_command 已经设置为你想要的命令。 ‌重启 …

Python 网络编程:端口检测与IP解析

Python 网络编程&#xff1a;端口检测与IP解析 在现代网络编程中&#xff0c;了解如何检查端口状态以及根据IP地址解析主机名是非常重要的技能。本文将介绍如何使用Python实现这两个功能&#xff0c;并提供相应的示例代码供读者参考。 一、检查端口是否打开 在网络应用中&am…

self.browser = web.WebView.New(self) NotImplementedError

这个错误是 NotImplementedError&#xff0c;通常意味着你正在调用的某个功能在当前环境或库版本中还没有实现或不支持。在这个错误中&#xff0c;问题出在 web.WebView.New(self)&#xff0c;它尝试创建一个 Web 浏览器控件&#xff0c;但未能成功。 在 wxPython 中&#xff…

Qt第十三天:网络编程:TCP和UDP的使用

我发现了有些人喜欢静静看博客不聊天呐&#xff0c; 但是ta会点赞。 这样的人呢帅气低调有内涵&#xff0c; 美丽大方很优雅。 说的就是你&#xff0c; 不用再怀疑哦 ❤️TCP&#xff1a; 一、创建项目&#xff0c;命名为Server&#xff0c;继承QWidget 二、添加Qt设计师…

一套医药订单管理系统。该系统旨在通过数字化手段,实现医药订单的自动化处理、库存精准管理、供应链高效协同,以及数据驱动的决策支持。

1.产品介绍 产品名称: 智医链医药订单一体化管理系统 主要功能: 智能订单处理 自动化订单接收:系统支持多渠道订单接入(如电商平台、医院采购系统、线下门店等),自动抓取订单信息,减少人工录入错误。智能分配与调度:根据库存情况、配送距离、车辆载重等因素,智能分配…

ios在复制方面的兼容

在 iOS 开发中&#xff0c;特别是在使用 JavaScript 与 WebView 交互时&#xff0c;可能会遇到某些事件处理的限制。iOS 对于非用户动作&#xff08;non-user-initiated actions&#xff09;的事件处理有特定的安全策略&#xff0c;这是为了防止恶意代码或自动化脚本执行可能导…

如何进行数学家式的学习思考?

如何进行数学家式的学习思考&#xff1f; 学生阶段的数学学习是非常重要的&#xff0c;对这一点很少有人质疑。一提起数学学习&#xff0c;一些学生、家长甚至一些教师认为&#xff0c;学生的数学学习往往侧重于掌握基本概念、公式和解题技巧&#xff0c;通过做题来巩固知识和提…

【飞腾加固服务器】全国产化解决方案:飞腾FT2000+/64核,赋能关键任务保驾护航

在信息安全和自主可控的时代背景下&#xff0c;国产化设备的需求与日俱增&#xff0c;尤其是在国防、航空航天、能源和其他关键行业。高可靠性和极端环境设计的国产加固服务器&#xff0c;搭载强大的飞腾FT2000/64核处理器&#xff0c;全面满足国产自主可控的严苛要求。 性能强…

数字化那点事:一文读懂人工智能

人工智能&#xff08;Artificial Intelligence, AI&#xff09;作为当今科技领域的热门话题&#xff0c;正以前所未有的速度改变着我们的生活。从智能家居到自动驾驶&#xff0c;从医疗诊断到金融分析&#xff0c;AI的应用无处不在。本文将通过通俗易懂的语言和丰富的案例&…

springboot 3.2.5集成spring security 只放行get请求,其他请求403

环境配置 jdk 17 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.2.5</version><relativePath/> <!-- lookup parent from repository --></…

Spring Boot 中的 @RequestMapping 和 Spring 中的 @RequestMapping 有什么区别?

在Spring框架中&#xff0c;RequestMapping注解用于映射Web请求到处理器&#xff08;控制器&#xff09;的方法上。在Spring Boot中&#xff0c;这个注解的使用方式并没有变化&#xff0c;但是Spring Boot作为Spring的扩展&#xff0c;提供了一些额外的便利性&#xff0c;使得开…