红黑树特点以及如何构建红黑树
红黑树的五大特点:
I、红黑树的五个性质:
1)每个结点要么是红的,要么是黑的。
2)根结点是黑的。
3)每个叶结点,即空结点(NIL)是黑的。
4)如果一个结点是红的,那么它的俩个儿子都是黑的。
5)对每个结点,从该结点到其子孙结点的所有路径上包含相同数目的黑结点。
II、红黑树插入的几种情况:
情况1,z的叔叔y是红色的。
情况2:z的叔叔y是黑色的,且z是右孩子
情况3:z的叔叔y是黑色的,且z是左孩子
III、红黑树删除的几种情况。
情况1:x的兄弟w是红色的。
情况2:x的兄弟w是黑色的,且w的俩个孩子都是黑色的。
情况3:x的兄弟w是黑色的,且w的左孩子是红色,w的右孩子是黑色。
情况4:x的兄弟w是黑色的,且w的右孩子是红色的。
除此之外,还得明确一点:
IV、我们知道,红黑树插入、或删除结点后,
可能会违背、或破坏红黑树的原有的性质,
所以为了使插入、或删除结点后的树依然维持为一棵新的红黑树,
那就要做俩方面的工作:
1、部分结点颜色,重新着色
2、调整部分指针的指向,即左旋、右旋。
V、并区别以下俩种操作:
1)红黑树插入、删除结点的操作,RB-INSERT(T, z),RB-DELETE(T, z)
2).红黑树已经插入、删除结点之后,
为了保持红黑树原有的红黑性质而做的恢复与保持红黑性质的操作。
如RB-INSERT-FIXUP(T, z),RB-DELETE-FIXUP(T, x)
以上这5点,我已经在我前面的2篇文章,都已阐述过不少次了,希望,你现在已经透彻明了。
---------------------------------------------------------------------
本文,着重图解分析红黑树插入、删除结点后为了维持红黑性质而做修复工作的各种情况。
[下文各种插入、删除的情况,与我的第二篇文章,红黑树算法的实现与剖析相对应]
ok,开始。
一、在下面的分析中,我们约定:
要插入的节点为,N
父亲节点,P
祖父节点,G
叔叔节点,U
兄弟节点,S
如下图所示,找一个节点的祖父和叔叔节点:
node grandparent(node n) //祖父
{
return n->parent->parent;
}
node uncle(node n) //叔叔
{
if (n->parent == grandparent(n)->left)
return grandparent(n)->right;
else
return grandparent(n)->left;
}
二、红黑树插入的几种情况
情形1: 新节点N位于树的根上,没有父节点
void insert_case1(node n) {
if (n->parent == NULL)
n->color = BLACK;
else
insert_case2(n);
}
情形2: 新节点的父节点P是黑色
void insert_case2(node n) {
if (n->parent->color == BLACK)
return; /* 树仍旧有效 */
else
insert_case3(n);
}
情形3:父节点P、叔叔节点U,都为红色,
[对应第二篇文章中,的情况1:z的叔叔是红色的。]
void insert_case3(node n) {
if (uncle(n) != NULL && uncle(n)->color == RED) {
n->parent->color = BLACK;
uncle(n)->color = BLACK;
grandparent(n)->color = RED;
insert_case1(grandparent(n)); //因为祖父节点可能是红色的,违反性质4,递归情形1.
}
else
insert_case4(n); //否则,叔叔是黑色的,转到下述情形4处理。
此时新插入节点N做为P的左子节点或右子节点都属于上述情形3,上图仅显示N做为P左子的情形。
情形4: 父节点P是红色,叔叔节点U是黑色或NIL;
插入节点N是其父节点P的右孩子,而父节点P又是其父节点的左孩子。
[对应我第二篇文章中,的情况2:z的叔叔是黑色的,且z是右孩子]
void insert_case4(node n) {
if (n == n->parent->right && n->parent == grandparent(n)->left) {
rotate_left(n->parent);
n = n->left;
} else if (n == n->parent->left && n->parent == grandparent(n)->right) {
rotate_right(n->parent);
n = n->right;
}
insert_case5(n); //转到下述情形5处理。
情形5: 父节点P是红色,而叔父节点U 是黑色或NIL,
要插入的节点N 是其父节点的左孩子,而父节点P又是其父G的左孩子。
[对应我第二篇文章中,情况3:z的叔叔是黑色的,且z是左孩子。]
void insert_case5(node n) {
n->parent->color = BLACK;
grandparent(n)->color = RED;
if (n == n->parent->left && n->parent == grandparent(n)->left) {
rotate_right(grandparent(n));
} else {
/* 反情况,N 是其父节点的右孩子,而父节点P又是其父G的右孩子 */
rotate_left(grandparent(n));
}
}
三、红黑树删除的几种情况
上文我们约定,兄弟节点设为S,我们使用下述函数找到兄弟节点:
struct node * sibling(struct node *n) //找兄弟节点
{
if (n == n->parent->left)
return n->parent->right;
else
return n->parent->left;
}
情况1: N 是新的根。
void
delete_case1(struct node *n)
{
if (n->parent != NULL)
delete_case2(n);
}
情形2:兄弟节点S是红色
[对应我第二篇文章中,情况1:x的兄弟w是红色的。]
void delete_case2(struct node *n)
{
struct node *s = sibling(n);
if (s->color == RED) {
n->parent->color = RED;
s->color = BLACK;
if (n == n->parent->left)
rotate_left(n->parent); //左旋
else
rotate_right(n->parent);
}
delete_case3(n);
}
情况 3: 兄弟节点S是黑色的,且S的俩个儿子都是黑色的。但N的父节点P,是黑色。
[对应我第二篇文章中,情况2:x的兄弟w是黑色的,且兄弟w的俩个儿子都是黑色的。
(这里,父节点P为黑)]
void delete_case3(struct node *n)
{
struct node *s = sibling(n);
if ((n->parent->color == BLACK) &&
(s->color == BLACK) &&
(s->left->color == BLACK) &&
(s->right->color == BLACK)) {
s->color = RED;
delete_case1(n->parent);
} else
delete_case4(n);
}
情况4: 兄弟节点S 是黑色的、S 的儿子也都是黑色的,但是 N 的父亲P,是红色。
[还是对应我第二篇文章中,情况2:x的兄弟w是黑色的,且w的俩个孩子都是黑色的。
(这里,父节点P为红)]
void delete_case4(struct node *n)
{
struct node *s = sibling(n);
if ((n->parent->color == RED) &&
(s->color == BLACK) &&
(s->left->color == BLACK) &&
(s->right->color == BLACK)) {
s->color = RED;
n->parent->color = BLACK;
} else
delete_case5(n);
}
情况5: 兄弟S为黑色,S 的左儿子是红色,S 的右儿子是黑色,而N是它父亲的左儿子。
//此种情况,最后转化到下面的情况6。
[对应我第二篇文章中,情况3:x的兄弟w是黑色的,w的左孩子是红色,w的右孩子是黑色。]
void delete_case5(struct node *n)
{
struct node *s = sibling(n);
if (s->color == BLACK)
if ((n == n->parent->left) &&
(s->right->color == BLACK) &&
(s->left->color == RED)) {
// this last test is trivial too due to cases 2-4.
s->color = RED;
s->left->color = BLACK;
rotate_right(s);
} else if ((n == n->parent->right) &&
(s->left->color == BLACK) &&
(s->right->color == RED)) {
// this last test is trivial too due to cases 2-4.
s->color = RED;
s->right->color = BLACK;
rotate_left(s);
}
}
delete_case6(n); //转到情况6。
情况6: 兄弟节点S是黑色,S的右儿子是红色,而 N 是它父亲的左儿子。
[对应我第二篇文章中,情况4:x的兄弟w是黑色的,且w的右孩子时红色的。]
void delete_case6(struct node *n)
{
struct node *s = sibling(n);
s->color = n->parent->color;
n->parent->color = BLACK;
if (n == n->parent->left) {
s->right->color = BLACK;
rotate_left(n->parent);
} else {
s->left->color = BLACK;
rotate_right(n->parent);
}
}
//呵呵,画这12张图,直接从中午画到了晚上。希望,此文能让你明白。
四、红黑树的插入、删除情况时间复杂度的分析
因为每一个红黑树也是一个特化的二叉查找树,
因此红黑树上的只读操作与普通二叉查找树上的只读操作相同。
然而,在红黑树上进行插入操作和删除操作会导致不再符合红黑树的性质。
恢复红黑树的属性需要少量(O(log n))的颜色变更(实际是非常快速的)和
不超过三次树旋转(对于插入操作是两次)。
虽然插入和删除很复杂,但操作时间仍可以保持为 O(log n) 次。
红黑树特点以及如何构建红黑树相关推荐
- 红黑树的删除_Python实现红黑树的删除操作
上一篇文章使用Python实现了红黑树的插入操作.参考:Python实现红黑树的插入操作本篇文章使用Python实现红黑树的删除操作.先将红黑树的5条特性列出来:1. 节点是红色或黑色.2. 根节点是 ...
- 底层实现红黑树_stl map底层之红黑树插入步骤详解与代码实现 | 学步园
本篇文章并没有详细的讲解红黑树各方面的知识,只是以图形的方式对红黑树插入节点需要进行调整的过程进行的解释. 最近在看stl源码剖析,看到map底层红黑树的实现.为了加深对于红黑树的理解就自己动手写了红 ...
- 红黑树的删除_从红黑树的本质出发,彻底理解红黑树!
前言 早上好,我是彤哥. 上一节,我们一起从二叉树.二叉查找树.平衡树.AVL树.2-3树.2-3-4树.B树,一路讲到红黑树,最后得出红黑树的本质:红黑树就是2-3-4树,请看下图: 我们知道2-3 ...
- 红黑树与平衡二叉树_图解“红黑树”原理,一看就明白!
" 学过数据结构都知道二叉树的概念,而又有多种比较常见的二叉树类型,比如完全二叉树.满二叉树.二叉搜索树.均衡二叉树.完美二叉树等. 图片来自 Pexels 今天我们要说的红黑树就是就是一棵 ...
- 真c++ 从二叉树到红黑树(6)之红黑树RedBlack
此文章为从二叉树到红黑树系列文章的第六节,主要介绍介绍红黑树,相信,有了之前BST,AVL和B树的铺垫,你会很快地理解红黑树.但红黑树的情况也十分复杂,因此,推荐分两天来看红黑树.一天看插入,一天 ...
- 为什么红黑树查询快_为什么红黑树的效率比较高
红黑树属于平衡二叉树.它不严格是因为它不是严格控制左.右子树高度或节点数之差小于等于1,但红黑树高度依然是平均log(n),且最坏情况高度不会超过2log(n). 红黑树(red-black tree ...
- 【动态图文详解-史上最易懂的红黑树讲解】手写红黑树(Red Black Tree)
红黑树:一棵自平衡(AVL)+二叉查找树(BST) 什么是红黑树 红黑树,Red-Black Tree 「RBT」是一个自平衡(不是绝对的平衡)的二叉查找树(BST). 红黑树是在1972年由Rudo ...
- 红黑树的红黑有什么意义_红枸杞和黑枸杞有什么不同?黑枸杞真的比红枸杞要好吗?...
"人到中年不得已,保温杯里泡枸杞"一句网络上流行的玩笑话,却也说明了枸杞在大众心中的认可度了.繁忙的工作和生活压力让处于亚健康状态的群体越来越多,不管是年轻人还是中老年人都开始关注 ...
- 长沙:借网红的风,铺长红的路
(图片来源于网络,侵删) 来源 | 螳螂观察 文 | 范柔丝 前段时间,外交部发言人赵立坚,在推特上向全球推介了长沙,让世界人民认识了这座网红城市.近日,赵立坚在个人微博上以一句"岳麓书院 ...
最新文章
- 闲鱼异地多活架构设计与实现
- 5G元年的世界电信日,我们的生活将如何被改变?
- 本质矩阵svd分解_SVD推荐系统
- C语言经典算法 11-20
- ConcurrentHashMap中的2的n次方幂上舍入方法
- android横向展示状态,【报Bug】Android横屏状态下启动App,即使在App.vue中锁定竖屏,但是首页nvue中的rpx单位是按照启动的横竖屏状态显示的!...
- Android kernel Crash后,定位出错点的方法
- 华为研制鸿蒙小米呢,直追华为鸿蒙!小米自研发操作系统发布
- 字节跳动面试:java实例化对象必须调用类的构造方法
- mysql视图 外键_Mysql之视图、索引、外键、触发器、事务
- error: cast from ‘void*’ to ‘int’ loses precision报错
- c#怎么拟合函数得到参数_c#怎么拟合函数得到参数_最小二乘法拟合任意次曲线(C#)...
- 了解一些FMS的基本概念
- C# DirectX.AudioVideoPlayback音频视频播放
- VSCode配置vue用户代码片段Snippets
- yolov5 行人 车辆 跟踪 检测 计数
- android horizontalscrollview 动画,Android 用HorizontalScrollView实现滑动标签tabView
- 天眼查 乱码 java_反爬虫解析-字体替换(天眼查/猫眼电影)
- u盘变o字节怎么修复_U盘变成0字节了数据怎么恢复
- 车载以太网交换机功能和应用案例汇总, 适用于AVB/TSN, 802.1AS(gPTP时钟同步)
热门文章
- 红海云签约中国中医药出版社,开启出版行业人力资源数字化新篇章
- Abaqus对复合材料进行建模的三种方式的对比
- 时间序列模型——AR、MA、ARMA、ARIMA
- 全球与中国塑料输送机滚筒市场深度研究分析报告
- Python:测试代码
- Web应用Word编辑
- 网络安全 社会工程学--钓鱼网站的制作和利用(让你了解整个钓鱼网站 背后的秘密.)
- java8 stream .skip() .limit() 实现分页功能
- Python爱好者 socket模块传输文件 -
- 东北大学OJ题解—1741: C语言编程测试2020-6-11-焦明海