红黑树-RBTree

目录

  • 1. 红黑树的概念
  • 2. 红黑树的性质
  • 3. 结点的定义
  • 4. 结点的插入
  • 5. 整体代码

1. 红黑树的概念

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

最短路径:全黑;最长路径:一黑一红交替。

由于avl树要求严格的平衡,因此相比于红黑树来说需要更频繁的旋转来保证平衡,所以整体而言效率是比红黑树要低一点。

在这里插入图片描述

2. 红黑树的性质

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

3. 结点的定义

//枚举颜色
enum Color {RED,BLACK
};template<class K, class V>
struct RBTreeNode {RBTreeNode(const pair<const K, V>& kv):_kv(kv), _left(nullptr), _right(nullptr), _parent(nullptr), _col(RED){ }pair<const K, V> _kv;//需要再增加一个结点颜色信息Color _col;RBTreeNode<const K, V>* _left;RBTreeNode<const K, V>* _right;//同样是需要父亲结点,后续调整旋转需要找到父亲RBTreeNode<const K, V>* _parent;
};

4. 结点的插入

往已经是满足红黑树性质的树中插入一个结点时,待插入结点的颜色一定要设置为红色,为什么?

若插入一个黑色结点,那么必然会违反性质4,若插入红色节点则不一定会违反性质3。

红黑树插入的关键在于要看叔叔结点的颜色,具体情况可分为两种:

  1. 叔叔存在且为红
    在这里插入图片描述
  2. 叔叔不存在或者叔叔存在且为黑
    在这里插入图片描述
    叔叔存在且为黑是第一种情况触发后才会出现:
    在这里插入图片描述

5. 整体代码

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

#pragma once
#include <iostream>using namespace std;enum Color {RED,BLACK
};template<class K, class V>
struct RBTreeNode {RBTreeNode(const pair<const K, V>& kv):_kv(kv), _left(nullptr), _right(nullptr), _parent(nullptr), _col(RED){}pair<const K, V> _kv;enum Color _col;RBTreeNode<const K, V>* _left;RBTreeNode<const K, V>* _right;RBTreeNode<const K, V>* _parent;
};template<class K, class V>
class RBTree {typedef RBTreeNode<const K, V> Node;
public:bool insert(const pair<const K, V>& kv) {if (!_root) {_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->_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;//parent为红需要一直往上调整while (parent && parent->_col == RED) {Node* grandpa = parent->_parent;if (grandpa->_left == parent) {Node* uncle = grandpa->_right;//叔叔存在且为红if (uncle && uncle->_col == RED) {//把父亲和叔叔染黑//爷爷染红继续往上调整parent->_col = uncle->_col = BLACK;grandpa->_col = RED;cur = grandpa;parent = cur->_parent;}//叔叔不存在或者存在且为黑else {//单纯的一边高(直线)单旋if (cur == parent->_left) {rotateRight(grandpa);parent->_col = BLACK;cur->_col = grandpa->_col = RED;}//折线情况需要双旋else {rotateLeft(parent);rotateRight(grandpa);cur->_col = BLACK;parent->_col = grandpa->_col = RED;}break;}}//同样的逻辑else {Node* uncle = grandpa->_left;if (uncle && uncle->_col == RED) {parent->_col = uncle->_col = BLACK;grandpa->_col = RED;cur = grandpa;parent = cur->_parent;}else {if (parent->_right == cur) {rotateLeft(grandpa);grandpa->_col = cur->_col = RED;parent->_col = BLACK;}else {rotateRight(parent);rotateLeft(grandpa);parent->_col = grandpa->_col = RED;cur->_col = BLACK;}break;}		 }}_root->_col = BLACK;return true;}bool isBlance() {if (_root->_col != BLACK) {return false;}int cnt = 0;Node* cur = _root;while (cur) {cnt += cur->_col == BLACK;cur = cur->_left;}return _isBlance(_root, 0, cnt);}int getHeight() {return getHeight(_root);}private:int getHeight(Node* root) {if (!root) {return 0;}int leftH = getHeight(root->_left);int rightH = getHeight(root->_right);return max(leftH, rightH) + 1;}bool _isBlance(Node* root, int blackcnt, int t) {if (!root) {cout << blackcnt << ' ' << t << endl;return t == blackcnt;}if (root->_col == RED && root->_parent && root->_parent->_col == RED) {return false;}return _isBlance(root->_left, blackcnt + (root->_col == BLACK), t) && _isBlance(root->_right, blackcnt + (root->_col == BLACK), t);}void rotateLeft(Node* parent) {Node* cur = parent->_right;Node* curleft = cur->_left;if (curleft) {curleft->_parent = parent;}parent->_right = curleft;cur->_left = parent;Node* oldparent = parent->_parent;parent->_parent = cur;cur->_parent = oldparent;if (!oldparent) {_root = cur;}else {if (oldparent->_left == parent) {oldparent->_left = cur;}else {oldparent->_right = cur;}}}void rotateRight(Node* parent) {Node* cur = parent->_left;Node* curright = cur->_right;if (curright) {curright->_parent = parent;}parent->_left = curright;cur->_right = parent;Node* oldparent = parent->_parent;parent->_parent = cur;cur->_parent = oldparent;if (!oldparent) {_root = cur;}else {if (oldparent->_left == parent) {oldparent->_left = cur;}else {oldparent->_right = cur;}}}private:Node* _root = nullptr;
};

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

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

相关文章

springboot苍穹外卖实战:九、小程序微信登录代码开发+商品浏览

微信登录 application.yml和application-dev.yml application-dev.yml sky:wechat:appid: xxxsecret: xxxapplication.yml sky:wechat:appid: ${sky.wechat.appid}secret: ${sky.wechat.secret}配置为微信用户生成jwt令牌时使用的配置项&#xff1a; application.yml sky…

长安链可验证数据库,保证数据完整性的可信存证方案

近日&#xff0c;长安链发布“可验证数据库”实现了链上链下协同存储及数据完整性保证&#xff0c;显著提升长安链存储能力的可扩展性。 可信存证是联盟链最典型的应用场景&#xff0c;被广泛应用在司法、工业、农业、贸易等领域。联盟链的存证应用主要分为两个阶段&#xff1…

04-Spring中Bean的作用域

Bean的作用域 scope的属性值 属性值作用singleton默认单例prototype原型每调用一次getBean()方法则获取一个新的Bean对象 , 每次注入的时候都是新对象request一个请求对应一个Bean仅限于在WEB应用中使用 , 需要引入web的框架如SpringMvc(global) session一个会话对应一个Bean…

10个python爬虫入门实例

昨天带伙伴学习python爬虫&#xff0c;准备了几个简单的入门实例&#xff0c;涉及主要知识点&#xff1a; web是如何交互的 requests库的get、post函数的应用 response对象的相关函数&#xff0c;属性 python文件的打开&#xff0c;保存 代码中给出了注释&#xff0c;并且…

通过easyexcel导出数据到excel表格

这篇文章简单介绍一下怎么通过easyexcel做数据的导出&#xff0c;使用之前easyui构建的歌曲列表crud应用&#xff0c;添加一个导出按钮&#xff0c;点击的时候直接连接后端接口地址&#xff0c;在后端的接口完成数据的导出功能。 前端页面完整代码 let editingId; let request…

Git被上锁无法进行操作解决办法

Git操作失败并提示Another git process seems to be running in this...... 比如&#xff0c;典型的&#xff1a; Another git process seems to be running in this repository, e.g. an editor opened by git commit. Please make sure all processes are terminated then t…

【Python】一篇带你掌握数据容器之列表

目录 前言&#xff1a; 一、列表 1.列表的定义 2.列表的下标索引 3.列表的常用操作 &#xff08;1&#xff09;index方法&#xff1a;查找某元素的下标 (2)修改特定位置下标的元素 &#xff08;3&#xff09;insert&#xff08;下标&#xff0c;元素&#xff09;方法&a…

基于SpringBoot+Vue的在线学习平台系统

基于SpringBootVue的在线学习平台系统的设计与实现~ 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBootMyBatisVue工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 主页 用户界面 登录界面 管理员界面 摘要 本文设计并实现了一套基于Spri…

Nuxt.js——基于 Vue 的服务端渲染应用框架

文章目录 前言一、知识普及什么是服务端渲染什么是客户端渲染&#xff1f;服务端渲染与客户端渲染那个更优秀&#xff1f; 二、Nuxt.js的特点Nuxt.js的适用情况&#xff1f; 三、Vue是如何实现服务端渲染的&#xff1f;安装依赖使用vue安装 Nuxt使用npm install安装依赖包使用n…

选择.NET 还是 Java?

1、.NET Framework的演变&#xff1a; .NET Framework&#xff1a; 最初由Microsoft引入&#xff0c;是一个Windows上的全功能框架。它包含了ASP.NET、Windows Presentation Foundation&#xff08;WPF&#xff09;、Windows Communication Foundation&#xff08;WCF&#xff…

基于springboot实现桥牌计分管理系统项目【项目源码】

基于springboot实现桥牌计分管理系统演示 JAVA简介 JavaScript是一种网络脚本语言&#xff0c;广泛运用于web应用开发&#xff0c;可以用来添加网页的格式动态效果&#xff0c;该语言不用进行预编译就直接运行&#xff0c;可以直接嵌入HTML语言中&#xff0c;写成js语言&#…

数据分析:智能企业七步曲(一)

原创&#xff1a; MicroStrategy微策略中国 作者&#xff1a;数据杰论 时间走到2018年最后一个季度&#xff0c;过去几年热炒的大数据概念正在各行各业开始落地并展开实际应用&#xff0c;核心是关注数据如何能为企业带来价值。因此&#xff0c;数据分析及其种种实现手段不断被…

基于飞蛾扑火算法优化概率神经网络PNN的分类预测 - 附代码

基于飞蛾扑火算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于飞蛾扑火算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于飞蛾扑火优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针对PNN神…

第一百七十一回 SearchBar组件

文章目录 1. 概念介绍2. 使用方法3. 代码与效果3.1 示例代码3.2 运行效果 4. 内容总结 我们在上一章回中介绍了"Material3中的IconButton"相关的内容&#xff0c;本章回中将 介绍SearchBar组件.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 我们在…

2023 ChinaJoy后,Flat Ads成为游戏、社交出海的新选择

今年ChinaJoy 展会&#xff0c;共吸引了来自世界各地的 500 多家企业参展&#xff0c;预计吸引超过33万人次参观。ChinaJoy年年有&#xff0c;那今年对于行业来说有什么新变化呢&#xff1f; 01 出海热潮不减&#xff0c;新增客户明显提升 据不完全统计&#xff0c;展会期间前…

《红蓝攻防对抗实战》十二.内网穿透之利用ICMP协议进行隧道穿透

内网穿透之利用ICMP协议进行隧道穿透 一.前言二.前文推荐三.利用ICMP协议进行隧道穿透1.ICMPsh获取反弹shell2.PingTunnel 搭建隧道 四.本篇总结 一.前言 本文介绍了利用ICMP协议进行隧道穿透的方法。ICMP协议不需要开放端口&#xff0c;可以将TCP/UDP数据封装到ICMP的Ping数据…

Error creating bean with name ‘apiModelSpecificationReader‘ defined in URL

问题&#xff1a; 启动项目的时候&#xff0c;报错了 org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name apiModelSpecificationReader defined in URL [jar:file:/D:/.gradle/caches/modules-2/files-2.1/io.springfox/sp…

基于springboot实现驾校管理系统项目【项目源码】

基于springboot实现驾校管理系统演示 JAVA简介 JavaScript是一种网络脚本语言&#xff0c;广泛运用于web应用开发&#xff0c;可以用来添加网页的格式动态效果&#xff0c;该语言不用进行预编译就直接运行&#xff0c;可以直接嵌入HTML语言中&#xff0c;写成js语言&#xff0…

【Windows网络编程】二.TCP套接字编程与主机上线实验

API&#xff1a; socket&#xff1a; 套接字函数创建绑定到特定传输服务提供程序的套接字。 函数原型&#xff1a;SOCKET WSAAPI socket([in] int af,[in] int type,[in] int protocol );参数&#xff1a; af&#xff1a;地址规范系列&#xff1a; AF_INET&#xff1a;IPv4&…

免费分享一套基于Springboot+Vue的在线考试系统,挺漂亮的

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的SpringbootVue的在线考试系统&#xff0c;分享下哈。 项目视频演示 【免费】springbootvue在线考试系统 Java毕业设计_哔哩哔哩_bilibili【免费】springbootvue在线考试系统 Java毕业设计项目来自互联网&a…