数据结构:搜索二叉树 | 红黑树 | 验证是否为红黑树

文章目录

        • 1.红黑树的概述
        • 2.红黑树的性质
        • 3.红黑树的代码实现
          • 3.1.红黑树的节点定义
          • 3.2.红黑树的插入操作
          • 3.3.红黑树是否平衡

黑红树是一颗特殊的搜索二叉树,本文在前文的基础上,图解红黑树插入:前文 链接,完整对部分关键代码展示,完整的代码在gitee仓库中: 链接
文章中有错误的地方,欢迎大家指正!如果有帮助到你,也请多多点赞支持!

1.红黑树的概述

平衡二叉树要求左右子树的高度差的绝对值不超过1,所以平衡二叉树是高度平衡的,正是因为它要求严格控制高度差,在频繁的插入的删除的时候导致旋转次数过多带来了一定的性能消耗!

红黑树也是一颗特殊的搜索二叉树,任何一条从根到叶子的路径上各个结点由颜色(红黑)方式的限制,红黑树确保没有一条路径会比其他路径长出两倍(最长路径不会超过最短路径的两倍),它而是接近平衡的。红黑树没有严格要求高度的平衡,所以红黑树在总体的性能上会略优于平衡二叉树(AVL树)。

在现实的各种应用中都是使用红黑树的来充当数据结构,如:Java集合中的TreeMap,C++STL中Set、Map等都是使用红黑树而不是AVL树。可能在查找方面AVL树会由于红黑树,但是几十次的常数差别,在现代CPU(大概每秒几十亿次)来说完全不受影响,AVL树和红黑树查找的时间复杂度都是在一个等级上O(log_2(N)),红黑树在插入和删除会优于AVL树!

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

在这里插入图片描述

关于路径问题

上图有11条路径

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

在这里插入图片描述

最短路径:全黑的路径 最长路径:一黑一红相间的路径

上面的图情况就是最大的(4个节点/2个节点 = 2倍)的情况!

3.红黑树的代码实现
3.1.红黑树的节点定义
enum color
{RED,BLACK
};template<class K, class V>
struct RBNode
{std::pair<K, V> _kv;RBNode<K, V>* _left;RBNode<K, V>* _right;RBNode<K, V>* _parent;color _color;RBNode(const std::pair<K, V> kv):_kv(kv), _left(nullptr), _right(nullptr), _parent(nullptr), _color(RED){}
};
3.2.红黑树的插入操作

第一大类情况:cur、parent为红,grandfather为黑,uncle存在且为红!

在这里插入图片描述

  1. 将parent和uncle都变为黑,grandfather变为红
  2. 但是grandfather,如果是根节点直接将其设为黑即可,
  3. 如果grandfather不为红,如下图:则将cur = grandfather继续重复步骤1和步骤2

在这里插入图片描述

**第二大类情况:**cur为红,parent为红,grandfather为黑,uncle不存在或uncle存在且为黑

单旋的情况:

  1. 下图是uncle不存在或uncle存在且为黑单旋的情况,通过节点的位置判断单旋:如条件是grandfather ->left = parent; parent->left = cur; 直线说明是单旋,都是左边说明右边高,要右单旋!
  2. 变色,grandfather变为红,parent变为黑色;可以看到,调整后的根据原来的grandfather是黑色,无论往上的祖先是何种颜色,都不会出现两个红色连一起的情况,不用往上调整了!

在这里插入图片描述

双旋的情况:

  1. 通过上面的例子可以知道,存在uncle且为黑和不存在uncle的处理结果是一样的!
  2. 通过下图的判断,是折线:grandfather ->left = parnt;parent->right =cur;通过平衡二叉树的插入操作的学习,可以知道,这种情况先左单旋,再右单旋!
  3. 变色:grandfather变为红,cur变为黑;可以看到,调整后的根据原来的grandfather是黑色,无论往上的祖先是何种颜色,都不会出现两个红色连一起的情况,不用往上调整了!

在这里插入图片描述

上面就是红黑树的**左子树的插入操作!右子树的插入99%是一样的!**可能没有99%,哈哈哈!但是是类似的操作!简单画个图:

第一大类情况

在这里插入图片描述

第二大类情况

单旋情况:

在这里插入图片描述

双旋情况:

在这里插入图片描述

bool insert(const std::pair<K, V>& kv)
{if (_root == nullptr){_root = new Node(kv);_root->_color = BLACK;return true;}Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_kv.first < kv.first){parent = cur;cur = cur->_right;}else if (cur->_kv.first > kv.first){parent = cur;cur = cur->_left;}else{return false;}}cur = new Node(kv);if (parent->_kv.first < kv.first){parent->_right = cur;}else{parent->_left = cur;}cur->_parent = parent;while (parent && parent->_color == RED){Node* grandfather = parent->_parent;// parent是左子树if (parent == grandfather->_left){Node* uncle = grandfather->_right;// 第一大类:uncle存在且为红if (uncle && uncle->_color == RED){// 改变颜色parent->_color = uncle->_color = BLACK;grandfather->_color = RED;// 修改条件,继续往上执行cur = grandfather;parent = cur->_parent;}else // 第二大类:uncle不存在或uncle存在且为黑{// 单旋情况if (cur == parent->_left){// 右单旋RotateRight(grandfather);// 改变颜色parent->_color = BLACK;grandfather->_color = RED;}else  // 双旋情况{RotateLeft(parent);RotateRight(grandfather);cur->_color = BLACK;grandfather->_color = RED;}// 这种情况就不用重复调整,直接跳出循环break;}}else // parent是右子树{Node* uncle = grandfather->_left;if (uncle && uncle->_color == RED){parent->_color = uncle->_color= BLACK;grandfather->_color = RED;cur = grandfather;parent = cur->_parent;}else{if (cur == parent->_right){RotateLeft(grandfather);parent->_color = BLACK;grandfather->_color = RED;}else{RotateRight(parent);RotateLeft(grandfather);cur->_color = BLACK;grandfather->_color = RED;}break;}}}// 根绝对为黑色_root->_color = BLACK;return true;
}
3.3.红黑树是否平衡

根据每条路径的黑节点的个数相同判断!

bool isBanlan()
{// 如何判断是否为红黑树// 1.高度行不行? 不行! 2.能不能根据节点的个数不操作2倍的关系? 也不行// 3.那有什么是确定的?所有路径黑节点的个数相等!根据这个性质!Node* cur = _root;int checkNum = 0;while (cur){if(cur->_color == BLACK)checkNum++;cur = cur->_left;}return isBanlan(_root,checkNum,0); 
}bool isBanlan(Node* root,int &checkNum,int blackNum)
{if (root == nullptr)return true;if (root->_color == BLACK){blackNum++;}if (root->_left == nullptr && root->_right == nullptr){return blackNum == checkNum ? true : false;}bool left = isBanlan(root->_left, checkNum, blackNum);bool right = isBanlan(root->_right, checkNum, blackNum);return left && right;
}

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

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

相关文章

uni-app 微信小程序之红包雨活动

文章目录 1. 页面效果2. 页面样式代码 1. 页面效果 GIF录屏有点卡&#xff0c;实际比较丝滑 每0.5s掉落一个红包控制4s后自动移除红包点击红包消除红包&#xff08;或者自行1&#xff0c;或者弹窗需求&#xff09; 2. 页面样式代码 <!-- 红包雨活动 --> <template>…

Ultraleap 3Di示例Interactable Objects组件分析

该示例代码位置如下&#xff1a; 分析如下&#xff1a; Hover Enabled&#xff1a;悬停功能&#xff0c;手放在这个模型上&#xff0c;会触发我们手放在这个模型上的悬停功能。此时当手靠近模型的时候&#xff0c;手的模型的颜色会发生改变&#xff0c;反之&#xff0c;则不会…

防御保护----防火墙的安全策略、NAT策略实验

实验拓扑&#xff1a; 实验要求&#xff1a; 1.生产区在工作时间&#xff08;9&#xff1a;00-18&#xff1a;00&#xff09;内可以访问DMZ区&#xff0c;仅可以访问http服务器&#xff1b; 2.办公区全天可以访问DMZ区&#xff0c;其中10.0.2.10可以访问FTP服务器和HTTP服务器…

【C++】类和对象(中篇)(全网最细!!!)

文章目录 &#x1f354;一、类的六个默认成员函数&#x1f354;二、构造函数&#x1f35f;1、概念&#x1f35f;2、特性&#x1f369;默认构造函数 &#x1f354;三、析构函数&#x1f35f;1、概念&#x1f35f;2、特性&#x1f369;默认析构函数 &#x1f354;四、拷贝构造函数…

了解WPF控件:ToggleButton和Separator常用属性与用法(十三)

掌握WPF控件&#xff1a;熟练ToggleButton和Separator常用属性&#xff08;十三&#xff09; ToggleButton 一个按钮类UI元素&#xff0c;它的特点是拥有两种状态&#xff1a;选中&#xff08;Checked&#xff09;和未选中&#xff08;Unchecked&#xff09;。当用户单击Togg…

用ChatGPT写申请文书写进常春藤联盟?

一年前&#xff0c;ChatGPT 的发布引发了教育工作者的恐慌。现在&#xff0c;各大学正值大学申请季&#xff0c;担心学生会利用人工智能工具伪造入学论文。但是&#xff0c;聊天机器人创作的论文足以骗过大学招生顾问吗&#xff1f; ChatGPT简介 ChatGPT&#xff0c;全称聊天生…

Docker 容器内运行 mysqldump 命令来导出 MySQL 数据库,自动化备份

备份容器数据库命令&#xff1a; docker exec 容器名称或ID mysqldump -u用户名 -p密码 数据库名称 > 导出文件.sql请替换以下占位符&#xff1a; 容器名称或ID&#xff1a;您的 MySQL 容器的名称或ID。用户名&#xff1a;您的 MySQL 用户名。密码&#xff1a;您的 MySQL …

SpringMVC-对静态资源的访问

1.工程中加入静态资源 在webapp下创建static文件夹&#xff0c;此文件夹专门放入静态资源 2.使项目可以处理静态资源的请求 在SpringMVC配置文件中添加以下语句 1.引入命名空间 xmlns:mvc"http://www.springframework.org/schema/mvc" xsi:schemaLocation“http…

npm i 报一堆版本问题

1&#xff0c;先npm cache clean --force 再下载 插件后缀加上 --legacy-peer-deps 2&#xff0c; npm ERR! code CERT_HAS_EXPIRED npm ERR! errno CERT_HAS_EXPIRED npm ERR! request to https://registry.npm.taobao.org/yorkie/download/yorkie-2.0.0.tgz failed, reason…

Nginx编译安装以及负载均衡配置(Ubuntu 22.04)

目录 Nginx编译安装以及负载均衡配置 Ubuntu 22.04.1 LTS 编译安装 nginx-1.22.1 1.安装依赖包 2. 下载nginx 3. 编译安装 报错解决 解决问题2 4.安装 5启动Nginx&#xff1a; 负载均衡 负载均衡算法 轮询 加权负载均衡 ip_hash算法 算法进行配置演示 加权负载均衡 轮询 IP 哈希…

活动回顾丨云原生技术实践营上海站「云原生 AI 大数据」专场(附 PPT)

AI 势不可挡&#xff0c;“智算”赋能未来。2024 年 1 月 5 日&#xff0c;云原生技术实践营「云原生 AI &大数据」专场在上海落幕。活动聚焦容器、可观测、微服务产品技术领域&#xff0c;以云原生 AI 工程化落地为主要方向&#xff0c;希望帮助企业和开发者更快、更高效地…

驱动开发-系统移植

一、Linux系统移植概念 需要移植三部分东西&#xff0c;Uboot ,内核 &#xff0c;根文件系统 &#xff08;rootfs&#xff09; &#xff0c;这三个构成了一个完整的Linux系统。 把这三部分学明白&#xff0c;系统移植就懂点了。 二、Uboot uboot就是引导程序下载的一段代…

C# 设置一个定时器函数

C#中&#xff0c;创建设置一个定时器&#xff0c;能够定时中断执行特定操作&#xff0c;可以用于发送心跳、正计时和倒计时等。 本文对C#的定时器简单封装一下&#xff0c;哎&#xff0c;以方便定时器的创建。 定义 using Timer System.Timers.Timer;class SetTimer {Timer …

npm create vue3项目特别慢

问题&#xff1a;Vue CLI v5.0.8在配置了淘宝镜像的情况下&#xff0c;创建项目报Failed to check for updates&#xff0c;还特别慢&#xff0c;等了好久都创建不好 查看 npm config get registry更换npm镜像 npm config set registryhttps://registry.npmmirror.com这样创建…

RC4加密技术探究:优缺点与实战应用

引言 在网络安全领域&#xff0c;加密技术一直是保障数据安全的重要手段。Rivest Cipher 4&#xff08;简称RC4&#xff09;作为一种对称加密算法&#xff0c;自20世纪80年代以来广泛应用于各种网络安全协议中。本文将详细分析RC4加密算法的优缺点以及其在实际应用中解决的问题…

AI大模型开发架构设计(6)——AIGC时代,如何求职、转型与选择?

文章目录 AIGC时代&#xff0c;如何求职、转型与选择&#xff1f;1 新职场&#xff0c;普通人最值钱的能力是什么?2 新职场成长的3点建议第1点&#xff1a;目标感第2点&#xff1a;执行力第3点&#xff1a;高效生产力 3 新职场会产生哪些新岗位机会?如何借势?4 新职场普通人…

ERROR Failed to get response from https://registry.npm.taobao.org/ 错误的解决

这个问题最近才出现的。可能跟淘宝镜像的证书到期有关。 解决方式一&#xff1a;更新淘宝镜像&#xff08;本人测试无效&#xff0c;但建议尝试&#xff09; 虽然无效&#xff0c;但感觉是有很大关系的。还是设置一下比较好。 淘宝镜像的地址&#xff08;registry.npm.taobao…

《30天自制操作系统》 第一周(D1-D7) 笔记

前言&#xff1a;这是我2023年5月份做的一个小项目&#xff0c;最终是完成了整个OS。笔记的话&#xff0c;只记录了第一周。想完善&#xff0c;却扔在草稿箱里许久。最终决定&#xff0c;还是发出来存个档吧。 一、汇编语言 基础指令 MOV: move赋值&#xff0c;数据传送指令…

【重点】【DP】123.买卖股票的最佳时机III

题目 法1&#xff1a;单次遍历&#xff0c;Best! class Solution {public int maxProfit(int[] prices) {int f1 -prices[0], f2 0, f3 -prices[0], f4 0;for (int i 1; i < prices.length; i) {f1 Math.max(f1, -prices[i]);f2 Math.max(f2, f1 prices[i]);f3 Ma…

交叉导轨为何要保持日常清洁?

在工业自动化的发展中&#xff0c;交叉导轨因其具有精度高、高刚性、高耐磨性等特点&#xff0c;在数控技术的发展中得到了越来越多的使用&#xff0c;对于交叉导轨来说&#xff0c;保持日常清洁对其性能和寿命具有重要意义。 1、防止灰尘和杂质的侵入&#xff1a;交叉导轨在机…