热门标签 | HotTags
当前位置:  开发笔记 > 人工智能 > 正文

数据结构红黑树的详解

这篇文章主要介绍了数据结构红黑树的详解的相关资料,数据结构中的二叉树查找,红黑树的讲解,需要的朋友可以参考下

数据结构 红黑树的详解

红黑树是具有下列着色性质的二叉查找树:

1.每一个节点或者着红色,或者着黑色。

2.根是黑色的。

3.如果一个节点是红色的,那么它的子节点必须是黑色。

4.从一个节点到一个NULL指针的每一条路径必须包含相同数目的黑色节点。

下面是一棵红黑树。


1.自底向上插入

通常把新项作为树叶放到树中。如果我们把该项涂成黑色,那么违反条件4,因为将会建立一条更长的黑节点路径。因此这一项必须涂成红色。如果它的父节点是黑色的,插入完成。如果父节点是红色的,那么违反条件3。在这种情况下我们必须调整该树以满足条件3。用于完成这项目任务的基本操作是颜色的改变和树的旋转。

如果新插入的节点的父节点是黑色,那么插入完成。

如果父节点是红色,那么有几种情形需要考虑。首先,假设这个父节点的兄弟是黑色(NULL节点约定为黑色)。这对于插入3或8是适用的,但对插入99不适用。令X是新加的树叶,P是它的父节点,S是该父节点的兄弟,G是祖父节点情况一:父节点的兄弟是黑色的。通过操作使得到达A,B,C的黑色路径保持不变(满足条件4),而且没有连续的红色节点(满足条件3).。



情况二:父节点的兄弟是红色的。



2.自顶向下删除

红黑树中的删除可以是自顶向下进行。每一件工作都归结于能够删除一片树叶。这是因为,要删除一个带有两个儿子的节点,我们用右子树上的最小节点代替它;该节点最多有一个儿子,然后将该节点删除。只有一个右儿子的节点可以用相同的方式删除,而只有一个左儿子的节点通过用其左子树上最大的节点替换,然后可将该节点删除。但是假如删除的节点不是红色的,那么就会破坏红黑树的平衡。解决的方法就是保证从上到下删除期间树叶是红色的。

在整个讨论中,令X为当前节点,T是它的兄弟,而P是它们的父亲。开始时我们把根涂成红色。当沿着树向下遍历时,我们设法保证X是红色的。当我们到达一个新的节点时,我们要确信P是红色的并且X和T是黑色的(因为不能有两个相连的红色节点)。存在两种主要情形。
情况一:X有两个黑色儿子。此时有三个子情况。
(1)T有两个黑儿子,那么我们可以翻转X、T、P的颜色来保持这种不变性。

(2)T的左儿子是红色的

(3)T的右儿子是红色的

情况二:X的儿子之一是红的。在这种情况下,我们落到下一层,得到新的X、T、P。如果幸运,X落在红儿子上。则我们继续前行。如果不是这样,那么我们知道T将是红的,而X和P将是黑的。我们可以旋转T和P,使得X的新父亲是红的;当然X和它的祖父是黑的。此时我们可以回到第一种主情况。

3.红黑树的实现
3.1 头文件
// 
// RedBlackTree.h 
// RedBlackTree3 
// 
// Created by Wuyixin on 2017/7/3. 
// Copyright © 2017年 Coding365. All rights reserved. 
// 
 
#ifndef RedBlackTree_h 
#define RedBlackTree_h 
 
#include  
#include  
#include  
 
 
typedef int ElementType; 
 
typedef enum { 
 RED, 
 BLACK 
} COLOR; 
 
typedef struct RedBlackNode *RedBlackTree,*Position; 
 
struct RedBlackNode{ 
 ElementType Element; 
 COLOR Color; 
 RedBlackTree Left; 
 RedBlackTree Right; 
}; 
 
static Position NullNode = NULL; 
static Position Header; 
static Position X,P,GP,GGP; 
/* 初始化 */ 
RedBlackTree Initialize(); 
/* 插入 */ 
RedBlackTree Insert(RedBlackTree T,ElementType Item); 
/* 删除 */ 
RedBlackTree Remove(RedBlackTree T,ElementType Item); 
/* 查找 */ 
Position Find(RedBlackTree T,ElementType Item); 
/* 遍历 */ 
void Travel(RedBlackTree T); 
 
 
 
 
#endif /* RedBlackTree_h */ 

3.2 实现文件

// 
// RedBlackTree.c 
// RedBlackTree3 
// 
// Created by Wuyixin on 2017/7/3. 
// Copyright © 2017年 Coding365. All rights reserved. 
// 
 
#include "RedBlackTree.h" 
 
 
/* 左旋转 */ 
static Position SingleRotateLeft(Position X); 
/* 右旋转 */ 
static Position SingleRotateRight(Position X); 
/* 旋转 */ 
static Position Rotate(Position Parent,Position* Origin ,ElementType Item); 
 
 
/* 左旋转 */ 
static Position SingleRotateLeft(Position T){ 
 Position TL = T->Left; 
 T->Left = TL->Right; 
 TL->Right = T; 
 return TL; 
} 
/* 右旋转 */ 
static Position SingleRotateRight(Position T){ 
 Position TR = T->Right; 
 T->Right = TR->Left; 
 TR->Left = T; 
 return TR; 
} 
 
/* 旋转 */ 
static Position Rotate(Position Parent,Position* Origin ,ElementType Item){ 
 if (Item Element){ 
 if (Origin != NULL) 
  *Origin = Parent->Left; 
 return Parent->Left = Item Left->Element ? 
 SingleRotateLeft(Parent->Left) : 
 SingleRotateRight(Parent->Left); 
 } 
 else{ 
 if (Origin != NULL) 
  *Origin = Parent->Right; 
 return Parent->Right = Item Right->Element ? 
 SingleRotateLeft(Parent->Right) : 
 SingleRotateRight(Parent->Right); 
 } 
 
} 
 
 
/* 初始化 */ 
RedBlackTree Initialize(){ 
 
 if (NullNode == NULL){ 
 NullNode = malloc(sizeof(struct RedBlackNode)); 
 if (NullNode == NULL) 
  exit(EXIT_FAILURE); 
 NullNode->Element = INT_MAX; 
 NullNode->Color = BLACK; 
 NullNode->Left = NullNode->Right = NullNode; 
  
 } 
 
 Header = malloc(sizeof(struct RedBlackNode)); 
 if (Header == NULL) 
 exit(EXIT_FAILURE); 
 
 /* header的值为无穷小,所以根插入到右边*/ 
 Header->Element = INT_MIN; 
 Header->Left = Header->Right = NullNode; 
 Header->Color = BLACK; 
 
 return Header; 
 
} 
 
static Position GetSibling(Position Parent,Position X){ 
 if (Parent->Element == INT_MIN) 
 return NULL; 
 if (X == Parent->Left) 
 return Parent->Right; 
 else if (X == Parent->Right) 
 return Parent->Left; 
 else 
 return NULL; 
} 
 
void HandleReorientForInsert(ElementType Item){ 
 Position Sibling,Origin; 
 
 /* 当P与X同时为红节点才进行调整 */ 
 if (X == NullNode || !(P->Color == RED && X->Color == RED)) 
 return ; 
 
 
 Sibling = GetSibling(GP, P); 
 
 if (Sibling == NULL) 
 return ; 
 
 
 /* GP,P,X是成字型,调整为一字型 */ 
 if ((GP->Element Element Color == BLACK){ 
  
 GP->Color = BLACK; 
 GP->Left->Color = RED; 
 GP->Right->Color = RED; 
  
 } 
 /* P的兄弟是红的 */ 
 else{ 
  
 GP->Color = RED; 
 GP->Left->Color = BLACK; 
 GP->Right->Color = BLACK; 
 } 
} 
 
RedBlackTree _Insert(RedBlackTree T,ElementType Item){ 
 
 if (T == NullNode){ 
 T = malloc(sizeof(struct RedBlackNode)); 
 T->Element = Item; 
 T->Left = T->Right = NullNode; 
 T->Color = RED; 
 } 
 else if (Item Element) 
 T->Left = _Insert(T->Left, Item); 
 else if (Item > T->Element) 
 T->Right = _Insert(T->Right, Item); 
 /* 重复值不插入 */ 
 
 X = P,P = GP,GP = GGP, GGP = T; 
 
 HandleReorientForInsert(Item); 
 
 return T; 
} 
 
/* 插入 */ 
RedBlackTree Insert(RedBlackTree T,ElementType Item){ 
 GGP = GP = P = X = NullNode; 
 T = _Insert(T, Item); 
 T->Right->Color = BLACK; 
 return T; 
} 
 
 
static void _HandleReorientForRemove(ElementType Item){ 
 RedBlackTree Sibling,R; 
 Sibling = GetSibling(P, X); 
 
 if (Sibling == NULL) 
 return ; 
 
 if (Sibling->Left->Color == BLACK && Sibling->Right->Color == BLACK){ 
 P->Color = BLACK; 
 X->Color = RED; 
 Sibling->Color = RED; 
 }else if(Sibling->Left->Color == RED){ 
 R = Sibling->Left; 
  
 P->Color = BLACK; 
 X->Color = RED; 
  
 R = Rotate(P, NULL, R->Element); 
 GP = Rotate(GP, NULL, R->Element); 
  
 }else if (Sibling->Right->Color == RED){ 
 X->Color = RED; 
 P->Color = BLACK; 
 Sibling->Color = RED; 
 Sibling->Right->Color = BLACK; 
  
 GP = Rotate(GP, NULL, Sibling->Element); 
  
 } 
} 
 
static void HandleReorientForRemove(RedBlackTree T, ElementType Item){ 
 RedBlackTree Sibling,Origin,OriginGP; 
 if (X == NullNode) 
 return ; 
 
 /* X有两个黑儿子 */ 
 if (X->Left->Color == BLACK && X->Right->Color == BLACK){ 
 _HandleReorientForRemove(Item); 
 }else{ 
  
 OriginGP = GP; 
 /* 落到下一层 */ 
 GP = P; P = X; 
  
 if (Item Element) 
  X = X->Left; 
 else 
  X = X->Right; 
  
  
 Sibling = GetSibling(P, X); 
 /* 如果X是黑的,则Sibling是红的,旋转 */ 
 if (X->Color == BLACK){ 
  GP = Rotate(GP, &Origin, Sibling->Element); 
  P = Origin; 
  GP->Color = BLACK; 
  P->Color = RED; 
  _HandleReorientForRemove(Item); 
  
 } 
  
 /* 恢复X,PX,GP。由于X是当前节点 如果当前节点正是Item,不恢复会影响查找 */ 
 if (X->Element == Item){ 
  X = P ; P = GP ;GP = OriginGP; 
 } 
  
 } 
} 
 
/* 删除 */ 
RedBlackTree Remove(RedBlackTree T,ElementType Item){ 
 
 ElementType Origin; 
 Position DeletePtr; 
 Origin = NullNode->Element; 
 
 NullNode->Element = Item; 
 
 GP = P = X = T; 
 
 /* 根染红 */ 
 T->Right->Color = RED; 
 
 while (X->Element != Item) { 
 GP = P ; P = X; 
 if (Item Element) 
  X = X->Left; 
 else 
  X = X->Right; 
  
 HandleReorientForRemove(T, Item); 
 } 
 
 
 NullNode->Element = Origin; 
 
 /* 找到 */ 
 if (X != NullNode){ 
 DeletePtr = X;  
 if (X->Left != NullNode){ 
  GP = P ; P = X; X = X->Left; 
  HandleReorientForRemove(T, Item); 
  /* 寻找左子树最大值替换 */ 
  while (X->Right != NullNode) { 
  GP = P ; P = X; 
  X = X->Right; 
  HandleReorientForRemove(T, Item); 
  } 
  if (X == P->Left) 
  P->Left = X->Left; 
  else 
  P->Right = X->Left; 
  
 }else if (X->Right != NullNode){ 
  GP = P ; P = X; X = X->Right; 
  HandleReorientForRemove(T, Item); 
  /* 寻找右子树最大值替换 */ 
  while (X->Left != NullNode) { 
  GP = P ; P = X; 
  X = X->Left; 
  HandleReorientForRemove(T, Item); 
  } 
  if (X == P->Left) 
  P->Left = X->Right; 
  else 
  P->Right = X->Right; 
 }else{ 
  /* X是树叶 */ 
  if (X == P->Left) 
  P->Left = NullNode; 
  else 
  P->Right = NullNode; 
 } 
  
 DeletePtr->Element = X->Element; 
 free(X); 
  
 } 
 
 /* 根染黑 */ 
 T->Right->Color = BLACK; 
 
 return T; 
} 
 
 
 
typedef enum { 
 ROOT, 
 LEFT, 
 RIGHT 
} NodeType; 
 
static char *TypeC; 
static char *ColorC; 
 
void _Travel(RedBlackTree T , NodeType Type){ 
 
 if (T != NullNode){ 
  
 if (Type == ROOT) 
  TypeC = "root"; 
 else if (Type == LEFT) 
  TypeC = "left"; 
 else if (Type == RIGHT) 
  TypeC = "right"; 
  
 if (T->Color == BLACK) 
  ColorC = "black"; 
 else 
  ColorC = "red"; 
  
 printf("(%d,%s,%s) ",T->Element,ColorC,TypeC); 
  
 _Travel(T->Left, LEFT); 
 _Travel(T->Right, RIGHT); 
  
 } 
 
} 
 
/* 遍历 */ 
void Travel(RedBlackTree T){ 
 _Travel(T->Right,ROOT); 
} 

3.3 调用

// 
// main.c 
// RedBlackTree3 
// 
// Created by Wuyixin on 2017/7/3. 
// Copyright © 2017年 Coding365. All rights reserved. 
// 
 
#include "RedBlackTree.h" 
int main(int argc, const char * argv[]) { 
   
  RedBlackTree T = Initialize(); 
   
  T = Insert(T, 10); 
  T = Insert(T, 85); 
  T = Insert(T, 15); 
  T = Insert(T, 70); 
  T = Insert(T, 20); 
  T = Insert(T, 60); 
  T = Insert(T, 30); 
  T = Insert(T, 50); 
  T = Insert(T, 65); 
  T = Insert(T, 80); 
  T = Insert(T, 90); 
  T = Insert(T, 40); 
  T = Insert(T, 5); 
  T = Insert(T, 55); 
  T = Insert(T, 100); 
   
   
  T = Remove(T, 100); 
   
   
  Travel(T); 
   
   
  return 0; 
} 

以上就是关于数据结构与算法中红黑二叉树的详解,如有疑问请留言或者到本站的社区讨论,感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!


推荐阅读
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • 生成对抗式网络GAN及其衍生CGAN、DCGAN、WGAN、LSGAN、BEGAN介绍
    一、GAN原理介绍学习GAN的第一篇论文当然由是IanGoodfellow于2014年发表的GenerativeAdversarialNetworks(论文下载链接arxiv:[h ... [详细]
  • [译]技术公司十年经验的职场生涯回顾
    本文是一位在技术公司工作十年的职场人士对自己职业生涯的总结回顾。她的职业规划与众不同,令人深思又有趣。其中涉及到的内容有机器学习、创新创业以及引用了女性主义者在TED演讲中的部分讲义。文章表达了对职业生涯的愿望和希望,认为人类有能力不断改善自己。 ... [详细]
  • 无线认证设置故障排除方法及注意事项
    本文介绍了解决无线认证设置故障的方法和注意事项,包括检查无线路由器工作状态、关闭手机休眠状态下的网络设置、重启路由器、更改认证类型、恢复出厂设置和手机网络设置等。通过这些方法,可以解决无线认证设置可能出现的问题,确保无线网络正常连接和上网。同时,还提供了一些注意事项,以便用户在进行无线认证设置时能够正确操作。 ... [详细]
  • 本文介绍了游戏开发中的人工智能技术,包括定性行为和非定性行为的分类。定性行为是指特定且可预测的行为,而非定性行为则具有一定程度的不确定性。其中,追逐算法是定性行为的具体实例。 ... [详细]
  • JavaScript设计模式之策略模式(Strategy Pattern)的优势及应用
    本文介绍了JavaScript设计模式之策略模式(Strategy Pattern)的定义和优势,策略模式可以避免代码中的多重判断条件,体现了开放-封闭原则。同时,策略模式的应用可以使系统的算法重复利用,避免复制粘贴。然而,策略模式也会增加策略类的数量,违反最少知识原则,需要了解各种策略类才能更好地应用于业务中。本文还以员工年终奖的计算为例,说明了策略模式的应用场景和实现方式。 ... [详细]
  • 本文介绍了PhysioNet网站提供的生理信号处理工具箱WFDB Toolbox for Matlab的安装和使用方法。通过下载并添加到Matlab路径中或直接在Matlab中输入相关内容,即可完成安装。该工具箱提供了一系列函数,可以方便地处理生理信号数据。详细的安装和使用方法可以参考本文内容。 ... [详细]
  • 本文详细介绍了相机防抖的设置方法和使用技巧,包括索尼防抖设置、VR和Stabilizer档位的选择、机身菜单设置等。同时解释了相机防抖的原理,包括电子防抖和光学防抖的区别,以及它们对画质细节的影响。此外,还提到了一些运动相机的防抖方法,如大疆的Osmo Action的Rock Steady技术。通过本文,你将更好地理解相机防抖的重要性和使用技巧,提高拍摄体验。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 无损压缩算法专题——LZSS算法实现
    本文介绍了基于无损压缩算法专题的LZSS算法实现。通过Python和C两种语言的代码实现了对任意文件的压缩和解压功能。详细介绍了LZSS算法的原理和实现过程,以及代码中的注释。 ... [详细]
  • 解决Cydia数据库错误:could not open file /var/lib/dpkg/status 的方法
    本文介绍了解决iOS系统中Cydia数据库错误的方法。通过使用苹果电脑上的Impactor工具和NewTerm软件,以及ifunbox工具和终端命令,可以解决该问题。具体步骤包括下载所需工具、连接手机到电脑、安装NewTerm、下载ifunbox并注册Dropbox账号、下载并解压lib.zip文件、将lib文件夹拖入Books文件夹中,并将lib文件夹拷贝到/var/目录下。以上方法适用于已经越狱且出现Cydia数据库错误的iPhone手机。 ... [详细]
  • JVM 学习总结(三)——对象存活判定算法的两种实现
    本文介绍了垃圾收集器在回收堆内存前确定对象存活的两种算法:引用计数算法和可达性分析算法。引用计数算法通过计数器判定对象是否存活,虽然简单高效,但无法解决循环引用的问题;可达性分析算法通过判断对象是否可达来确定存活对象,是主流的Java虚拟机内存管理算法。 ... [详细]
  • 本文介绍了数模国赛的报名参加方法,包括学校报名和自己报名的途径。同时给出了建模竞赛的建议,重在历练的同时掌握方法以及弥补自己的短板。此外,还分享了论文的结构和模型求解部分的注意事项,包括数学命题的表述规范和计算方法的原理等。 ... [详细]
  • 本文介绍了高校天文共享平台的开发过程中的思考和规划。该平台旨在为高校学生提供天象预报、科普知识、观测活动、图片分享等功能。文章分析了项目的技术栈选择、网站前端布局、业务流程、数据库结构等方面,并总结了项目存在的问题,如前后端未分离、代码混乱等。作者表示希望通过记录和规划,能够理清思路,进一步完善该平台。 ... [详细]
author-avatar
如果-不曾开始_632
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有