手撕红黑树
学了很久编程了,红黑树在我们耳边早就如雷贯耳,都说他是数据结构中最难的几种结构了,但是,实际上学会了之后,你会发现他还是很简单的,个人认为他还没有AVL树的旋转难,好了,老规矩,来上代码:
#pragma once
#pragma once
#include <iostream>
#include <set>
#include <map>
#include <assert.h>
#include <math.h>
#include <vector>
using namespace std;
namespace cc
{enum colour{RED,BLACK};template<class K, class V>struct RBtreenode{colour _col;pair<K, V> _val;RBtreenode<K, V>* _left;RBtreenode<K, V>* _right;RBtreenode<K, V>* _parent;RBtreenode(const pair<K, V>& x):_val(x), _left(nullptr), _right(nullptr), _parent(nullptr), _col(RED){}};template<class K, class V>class RBtree{public:typedef RBtreenode<K, V> node;void reor(node* parent){node* sub = parent->_left;node* subr = sub->_right;if (_root == parent){_root = sub;sub->_parent = nullptr;sub->_right = parent;parent->_parent = sub;parent->_left = subr;if (subr)subr->_parent = parent;}else{node* pparent = parent->_parent;if (pparent->_left == parent)pparent->_left = sub;elsepparent->_right = sub;sub->_parent = pparent;sub->_right = parent;parent->_parent = sub;parent->_left = subr;if (subr)subr->_parent = parent;}}void reol(node* parent){node* sub = parent->_right;node* subl = sub->_left;if (_root == parent){_root = sub;sub->_parent = nullptr;sub->_left = parent;parent->_parent = sub;parent->_right = subl;if (subl)subl->_parent = parent;}else{node* pparent = parent->_parent;if (pparent->_left = parent)pparent->_left = sub;elsepparent->_right = sub;sub->_parent = pparent;sub->_left = parent;parent->_parent = sub;parent->_right = subl;if (subl)subl->_parent = parent;}}bool insert(const pair<K, V>& x){if (_root == nullptr){_root = new node(x);_root->_col = BLACK;return true;}node* parent = nullptr;node* cur = _root;while (cur){if (x.first < cur->_val.first){parent = cur;cur = cur->_left;}else if (x.first > cur->_val.first){parent = cur;cur = cur->_right;}elsereturn false;}cur = new node(x);if (parent->_val.first > x.first)parent->_left = cur;elseparent->_right = cur;cur->_parent = parent;node* grandfather = parent->_parent;while (parent && parent->_col == RED){if (grandfather->_left == parent){node* uncle = grandfather->_right;//情况一:只染色if (uncle && uncle->_col == RED){uncle->_col = BLACK;parent->_col = BLACK;grandfather->_col = RED;if (grandfather == _root){grandfather->_col = BLACK;break;}}//情况二+三:旋转+染色else if (uncle && uncle->_col == BLACK){if (parent->_left == cur){//单旋reor(grandfather);//染色grandfather->_col = RED;parent->_col = BLACK;}else{//双旋reol(parent);reor(grandfather);//染色cur->_col = BLACK;//爷爷节点变红grandfather->_col = RED;}break;}else if (uncle == nullptr){if (parent->_left == cur){reor(grandfather);grandfather->_col = RED;parent->_col = BLACK;}else{reol(parent);reor(grandfather);grandfather->_col = RED;cur->_col = BLACK;}break;}}else{node* uncle = grandfather->_left;if (uncle && uncle->_col == RED){uncle->_col = BLACK;parent->_col = BLACK;grandfather->_col = RED;if (_root == grandfather){grandfather->_col = BLACK;break;}}else if (uncle && uncle->_col == BLACK){if (parent->_left == cur){reor(parent);reol(grandfather);grandfather->_col = RED;cur->_col = BLACK;}else{reol(grandfather);grandfather->_col = RED;parent->_col = BLACK;}break;}else if (uncle == nullptr){if (parent->_left = cur){reor(parent);reol(grandfather);cur->_col = BLACK;grandfather->_col = RED;}else{reol(grandfather);parent->_col = BLACK;grandfather->_col = RED;}break;}}cur = grandfather;parent = cur->_parent;grandfather = parent->_parent;}return true;}bool check(){return _check(_root);}void print(){prin(_root);}void prin(node* root,int num){if (root == nullptr)return;if (root->_col == BLACK)num++;if (root->_left == root->_right &&root->_left == nullptr)cout << num << endl;prin(root->_left,num);prin(root->_right,num);}bool _check(node* root){if (root == nullptr){if (root->_col != BLACK)exit(-1);return true;}if (root->_parent && root->_parent->_col == RED){cout << "异常退出" << endl;exit(-1);}int num = 0;prin(root, num);}private:node* _root = nullptr;};
}
其实和AVL树的代码差不多,唯一不同的是,我们没有平衡因子了,但是有颜色。
下面来说说红黑树的规则:
1.一个节点不是红色就是黑色
2.根节点必须是黑色
3.红色节点的两个孩子必须是黑色节点
4.每条路径的黑色节点个数相同
5.叶子结点(NIL节点)是黑色的
上面就是红黑树的规则,红黑树的代码就在上面,现在说一下红黑树的具体实现规则:
1.如果叔叔节点存在且叔叔节点为红色,那么,把父节点和叔叔节点染成黑色,组父节点染成红色,如果此时的祖父节点是根节点,那么,就在把祖父节点染成黑色。如果不是,就把新插入的节点更新成祖父节点,依次往上更新,直到父节点为空或是父节点的颜色为黑色就停止。
2.如果叔叔节点存在,且叔叔节点是黑色的,那么此时就要判断新插入的节点在父节点的左还右,如果父节点,祖父节点,新插入的节点成一条线,那么此时就是单旋,然后旋转完成之后把父节点染成黑色,祖父节点染成红色。
3.如果叔叔节点存在,且为黑色,新插入节点与父节点,祖父节点形成折线,那么此时应该是双旋,旋转完成之后,把新插入的节点染成黑色,祖父节点染成红色。
4.如果叔叔节点不存在,那就看是上面的额那种情况,是那种旋转,找到对应的旋转就好了。
以上就是实现红黑树代码的具体细节。
AVL树和红黑树的对比:
其实AVL树和红黑树两个各有各的好处,是的,个人认为两个各有各的好处,因为AVL对树高比较严格,所以导致旋转点额次数就多,所以就会有额外的消耗,但是红黑树就没有这么多的消耗了,因为红黑树的上面几个规则,导致红黑树最长路径不得超过对短路径的两倍,所以,红黑树也会旋转,但是插入同等节点的条件下,红黑树旋转点次数肯定比AVL树少,但是AVL树是严格的logn,而红黑树是不太严格的logn,所以我说是各有各的好。
以上就是红黑树的规则讲解以及代码实现。希望大家能够多多支持!!谢谢!
相关文章:
手撕红黑树
学了很久编程了,红黑树在我们耳边早就如雷贯耳,都说他是数据结构中最难的几种结构了,但是,实际上学会了之后,你会发现他还是很简单的,个人认为他还没有AVL树的旋转难,好了,老规矩&am…...
举例说明自然语言处理(NLP)技术
自然语言处理(NLP)技术是一种人工智能领域的技术,用于处理自然语言文本或语音信号。下面是一些自然语言处理技术的例子: 机器翻译:机器翻译是一种自然语言处理的技术,它可以将一种语言的文本翻译成另一种语…...
淘宝详情API接口在各种应用中的作用性
标题:淘宝详情API接口在各种应用中的作用性 一、引言 随着互联网的快速发展和电子商务的广泛应用,淘宝作为中国最大的C2C电商平台,其提供的API接口在各种应用中发挥着越来越重要的作用。本文将详细介绍淘宝详情API接口的背景、定义、类型&a…...
java用正则方法验证文件名是否合法
Java中用到文件操作时,经常要验证文件名是否合法. 用File类的createNewFile()方法的确很管用.但当要批量验证时,效率上就会有问题.正则匹配的开销比创建文件少了很多. 那么一个合法的文件(Win下)应该符合如下规则: 1.文件名不能为空,空在这里有两个意思: 文件名(包括扩展名…...

【learnopengl】Assimp构建与编译
文章目录 【learnopengl】Assimp构建与编译1 前言2 Assimp构建与编译2.1 下载源码2.2 CMake构建2.3 VS2022编译 3 在VS中配置Assimp库4 验证 【learnopengl】Assimp构建与编译 1 前言 最近在跟着LearnOpenGL这个网站学习OpenGL,这篇文章详细记录一下教程中关于Ass…...

小兔鲜商02
npm i vueuse/core -fvue插件使用: 许多公用的全局组件,,可以通过插件注册进去,就不用一个一个导入组件,, import XtxSkeleton from /components/library/xtx-skeletonexport default {install (app) {// …...
一键替换工程文件和场景中的UI对象字体
具体流程: 找到工程中使用到的所有字体找到工程和场景中包含Text的所有对象展示要替换的字体名字让用户选择通过用户选择的字体,展示响应的物体对象一键替换 通过AssetDatabase.FindAssets找到工程中包含的所有字体: private List<strin…...

微信小程序编辑器代码格式缩进设置
第一步点击这个编辑器设置: 然后设置tab为空格,并且设置占几个空格,这里是4个空格。 这样就好了,文件保存就会自动设置好缩进格式了。...

Android Aidl跨进程通讯(二)--异常捕获处理
学更好的别人, 做更好的自己。 ——《微卡智享》 本文长度为1623字,预计阅读5分钟 前言 上一篇《Android Aidl跨进程通讯的简单使用》中介绍了跨进程的通讯处理,在进程间的数据通过Aidl实现了交互,项目中经常会遇到Bug,…...
Android中OkHttp源码阅读二(责任链模式)
博主前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住也分享一下给大家 👉点击跳转到教程 Android OkHttp源码阅读详解一 看OkHttp源码,发现OkHttp里面使用了责任链设计模式,所以才要学习…...

2023年03月 C/C++(六级)真题解析#中国电子学会#全国青少年软件编程等级考试
C/C++编程(1~8级)全部真题・点这里 第1题:波兰表达式 波兰表达式是一种把运算符前置的算术表达式,例如普通的表达式2 + 3的波兰表示法为+ 2 3。波兰表达式的优点是运算符之间不必有优先级关系,也不必用括号改变运算次序,例如(2 + 3) * 4的波兰表示法为* + 2 3 4。本题求解…...

顺序表链表OJ题(1)——【LeetCode】
W...Y的主页 😊 代码仓库分享 💕 前言: 今天我们来回顾一下顺序表与链表,针对这一块我们也有许多OJ题目供大家参考。当我们学习完顺序表链表后避免不了一些习题的练习,这样才能巩固我们学习的内容。 话不多说…...
flex:1
问题1:“flex: 1” 与其他 “flex” 值有何区别? 答案: “flex: 1” 是 “flex” 属性的一种简写形式,它将 “flex-grow”、“flex-shrink” 和 “flex-basis” 设置为特定的值。与其他 “flex” 值相比,“flex: 1” …...

iOS练手项目知识点汇总
基础理解篇 Objective-C是一种面向对象的编程语言,它支持元编程。元编程是指编写程序来生成或操纵其他程序的技术。 Objective-C中,元编程可以使用Objective-C的动态特性来实现。例如可以使用Objective-C的运行时函数来动态地创建类、添加属性和方法等等…...

【Linux】Libevent相关小知识总结
Libevent是基于事件的,也就是说,相当于去注册一个事件,当这个事件发生的话,那么就会调用回调函数。...
【Spring Security】UserDetailsService 接口介绍
文章目录 UserDetailsService 介绍UserDetailsService 具体操作UserDetailsService 方法介绍 UserDetailsService 介绍 UserDetailsService 在 Spring Security 中主要承担查询系统内用户、验证密码、封装用户信息和角色权限。大白话就是你写一个实现类实现 UserDetailsServic…...

Mybatis学习|日志工厂、分页
1.日志工厂 如果一个数据库操作,出现了异常,我们需要排错。日志就是最好的助手! 曾经: sout、debug 现在:日志工厂! 我们主要掌握STDOUT_LOGGING 和LOG4j 在Mybatis中具体使用哪个一日志实现,在设置中设定! 在mybatis核心配置文件中&#…...

Vivado 添加FPGA开发板的Boards file的添加
1 digilent board file 下载地址 下载地址 : https://github.com/Digilent/vivado-boards 2 下载后 3 添加文件到 vivado 安装路径 把文件复制到 Vivado\2019.1\data\boards\board_files4 创建工程查看是否安装成功...
vmstat
vmstat VirtualMeomoryStatistics,虚拟内存统计,是Linux中监控内存的常用工具,可对操作系统的虚拟内存、进程、CPU等的整体情况进行监视。 [rootwenzi wenzi]# vmstat procs -----------memory---------- ---swap-- -----io---- -system--…...

LinuxShell变量
变量: 命名规则: 在Shell中,变量名可以由字母、数字或者下划线组成,并且只能以字母或者下划线开头。对于变量名的长度,Shell并没有做出明确的规定。因此,用户可以使用任意长度的字符串来作为变量名。但是…...
Python爬虫实战:研究MechanicalSoup库相关技术
一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...

使用VSCode开发Django指南
使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...
STM32+rt-thread判断是否联网
一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢
随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...

【堆垛策略】设计方法
堆垛策略的设计是积木堆叠系统的核心,直接影响堆叠的稳定性、效率和容错能力。以下是分层次的堆垛策略设计方法,涵盖基础规则、优化算法和容错机制: 1. 基础堆垛规则 (1) 物理稳定性优先 重心原则: 大尺寸/重量积木在下…...

消防一体化安全管控平台:构建消防“一张图”和APP统一管理
在城市的某个角落,一场突如其来的火灾打破了平静。熊熊烈火迅速蔓延,滚滚浓烟弥漫开来,周围群众的生命财产安全受到严重威胁。就在这千钧一发之际,消防救援队伍迅速行动,而豪越科技消防一体化安全管控平台构建的消防“…...

客户案例 | 短视频点播企业海外视频加速与成本优化:MediaPackage+Cloudfront 技术重构实践
01技术背景与业务挑战 某短视频点播企业深耕国内用户市场,但其后台应用系统部署于东南亚印尼 IDC 机房。 随着业务规模扩大,传统架构已较难满足当前企业发展的需求,企业面临着三重挑战: ① 业务:国内用户访问海外服…...
数据库——redis
一、Redis 介绍 1. 概述 Redis(Remote Dictionary Server)是一个开源的、高性能的内存键值数据库系统,具有以下核心特点: 内存存储架构:数据主要存储在内存中,提供微秒级的读写响应 多数据结构支持&…...
深入理解 React 样式方案
React 的样式方案较多,在应用开发初期,开发者需要根据项目业务具体情况选择对应样式方案。React 样式方案主要有: 1. 内联样式 2. module css 3. css in js 4. tailwind css 这些方案中,均有各自的优势和缺点。 1. 方案优劣势 1. 内联样式: 简单直观,适合动态样式和…...