前言
最近在复习数据结构,复习到红黑树在b站看了几个视频都感觉云里雾里,于是看书总结,记录一下方便自己以后查看。
一、为什么要有红黑树?
我们知道二叉平衡树的查找效率很高,在log(n)这个数量级,但是为了维护树的平衡性质,在插入和删除结点的时候要经常进行左旋和右旋操作,如果我们需要经常插入和删除结点,那么我们很大的开销就在维护这棵树的平衡上,于是红黑树的优势就体现出来了。
首先红黑树不是一颗平衡树,它由红黑的规则来保持一个大致的“平衡”,让红黑树的查找效率也在log(n)这个量级。此外,红黑树只需要一个大致的“平衡”,所以减少了调整树结构的频率。做到了既有很高的查找效率,又减少了维护成本。
二、红黑树的定义
1.首先红黑树是一棵二叉排序树
红黑树需要满足二叉排序树的规则,此处不再赘述。
2.红黑性质
在满足二叉排序树的基础上,红黑树有以下五条红黑性质:
- 每个结点是红色或者黑色的。
- 根结点是黑色的。
- 叶结点(以前学习的二叉树中叶子结点的子结点,即null结点)是黑色的。
- 不存在相邻的红结点,即红结点的父结点和子结点都是黑的。
- 每个结点到任一叶结点的简单路径上,所含黑结点的数量相同。
通过这两组约束来保持红黑树大致的“平衡”,确保其查找效率,下面的插入操作中就是将插入结点后的树调整为符合这些性质。
三、红黑树的插入
当插入一个结点时如果破坏了二叉排序树或者红黑树的性质,我们就需要调整,调整分为旋转(左旋和右旋)和染色两部分,使添加结点后的树保持是一棵红黑树。首先我们都假设插入结点是红色的,因为插入一个红结点不会增加路径上黑结点的数量,避免破坏性质5。再分情况讨论。
插入一个新红结点时分为以下三种情况:
- 插入的结点是根结点。
- 插入结点的父结点是黑色的。
- 插入结点的父结点是红色的。
①插入的结点是根结点
将其染成黑色,结束。
②插入结点的父结点是黑色的
插入后没有破坏红黑树任何性质,无需调整,结束。
③插入结点的父结点是红色的
此时出现了两个红结点相邻的情况,需要调整,调整的方法又需要根据插入结点的叔结点(其父结点的兄弟结点)的颜色来考虑,因为null结点被认为是黑结点了,所以父结点一定有兄弟结点。分为(1)叔结点是黑色的和(2)叔结点是红色的两种情况。
1.叔结点是黑色的
和平衡二叉树一样有LL,LR,RL,RR四种插入位置,我们假设新插入结点为Z,父结点为A,爷结点为B,叔结点未画出,因为我们不需要调整叔结点,和平衡二叉树一样只要在旋转时将叔结点连到相应的位置就可以。
Z是爷结点左孩子的左孩子(LL):将Z的父结点右旋,此时Z的父结点成为“根”结点,将Z的父结点和原爷结点(此时是“根结点”的右孩子)交换颜色,调整完成。
Z是爷结点左孩子的右孩子(LR):Z左旋(此时形成和LL相同的结构),再右旋,Z与原爷结点(此时为Z的右孩子)交换颜色,调整完成。
注意:图中Z左旋后与A交换了名字,为了形成与LL一样的结构,但结点并没有交换。
RR和RL是另外两种对称的情况,可以自己画图尝试一下。
Z是爷结点的右孩子的右孩子(RR):Z的父结点左旋,Z的父结点与Z原爷结点(此时为“根结点”的左孩子)交换颜色,调整完成。
Z是爷结点的右孩子的左孩子(RL):Z先右旋,此时形成与RR相同结构,Z再左旋,再与原Z的爷结点(此时为Z的左孩子)交换颜色,调整完成。
2.叔结点是红色的
此时Z的父结点,叔结点,爷结点都需要调整。
Z有四种插入位置,四种位置都做相同的调整,将Z的父结点和叔结点染黑,将Z的爷结点染红。此时局部的树已经完成调整。
但是由于将Z的爷结点染红了,所以在B结点往上的树中可能出现问题,于是将B结点认为是新插入的结点进行调整,只要满足这种情况就会一直循环,新插入的结点指针Z会一直上移。直到跳出这种情况。
至此,红黑树的插入操作就完成了。
总结
其实感觉考试是不可能考红黑树的大题,最多有个选择题,还有一个红黑树的删除操作,还没看,那个情况会更复杂一些,有空再写吧。