#这个可以自己画画图
https://www.cs.usfca.edu/~galles/visualization/RedBlack.html
NII是虚拟出来的
找到圆心(一定是子节点)和旋转的节点
p绕c节点
只要旋转,子树资源互换了,祖父母都降级了,要不给点好处,所有把原来的子树抢过来,给父母了
左旋转
右选转
叔叔没有子节点,就是nil 也是null
红黑树插入所有的情况
红黑树具有如下性质:
- 红黑树是一颗平衡二叉树搜索树,其中序遍历单调不减
- 节点是红色或黑色
- 根节点是黑色
- 每个叶节点(也有称外部节点的,目的是将红黑树变为真二叉树,即NIL节点,空节点)是黑色的
- 每个红色节点的两个子节点都是黑色。(换句话说,从每个叶子到根的所有路径上不能右两个连续的红色节点)
- 从根节点到每个叶子的所有路径都包含相同数目的黑色节点(这个数值叫做黑高度)我们在任何一个分支上去找的时候黑色节点的个数要是相同的
经过上面的定义,我们可以发现下面几个事实:
- 两个红节点不能相连接
- 从x到x的后代叶子节点的路径上,黑色节点的数量是相同的。我们可以把这个数量定义称为bh(x).其中不包含x
- 从根节点到叶节点的长度差不会超过一倍
- 包含n个内部节点的红黑树,height <= 2long(n+1)
回顾下 左旋和右选
情况1: 插入的是根节点
原树是空树,此情况只会违反性质2
对策: 直接把此节点涂为黑色
情况2: 插入的节点的父节点是黑色
此不会违反性质2和性质4,红黑树没有被破坏
对策: 什么也不做
情况3: 插入当前节点是4,它的父节点是红色且父亲的兄弟节点(叔叔节点)是红色
对策将当前节点的父节点和叔叔节点涂黑,爷爷节点涂红(就是7),把当前节点(2)指向爷爷节点,从新的当前节点重新开始算法
情况4:当前节点(目前就是7)的父节点是红色,叔叔节点是黑色(父亲的兄弟节点),当前节点(目前是7)是其父节点的右子
对策 当前节点(目前是7)的父节点做为新的当前节点,当前节点是其父节点的右子
对策:当前节点的父节点做为新的当前节点,以新当前节点为支点左旋
情况5: 当前节点(目前是2了)的父节点是红色,叔叔节点是黑色(父节点的兄弟是14),当前节点是其父节点的左子
对策当前节点(目前是2)的父节点做为新的当前节点,以新当前节点为支点右选。颜色也要改变
变化后
在一次详细解说下
插入:
将需要插入的元素z按照常规的二叉搜索树进行插入,颜色是红色
然后需要处理对于红黑树的定义违反之处
根节点是红色的,那么就让根节点变成黑色
z和z的父节点都是红色的,处理这种情况,总共有三种
六种冲突情况的处理,假设新加入的节点是z:
一、. 父节点和父节点的兄弟节点都是红色的处理方法
- 将插入z的父节点和父的兄弟节点都变成黑色
- 将z的祖父节点变成红色
- z的祖父节点变成红色后,循环处理冲突
二、 当我们插入的z节点,z的父节点是红色,父亲的兄弟节点是黑色,z的父节点是左孩子,z是右孩子 —这样是左移
- 在z的父节点执行左移动操作
- 让z的左孩子称为新的新插入的z节点,继续处理冲突
上图返过来
z的父节点是红色,z父亲节点兄弟是黑色,z的父节点是右孩子,z是左孩子 --这样是右移
- 在z的父亲节点执行右移操作
- 让z的右孩子称为新的新插入的z节点,继续处理冲突
三、z的父节点是红色,z的父节点兄弟是黑色,z的父节点是左孩子,z是左孩子
- 在z的祖父节点右移一次
- 将z的parent和z的兄弟节点交换颜色
z的父节点是红色,z的父节点的兄弟是黑色,z的父节点是右孩子,z是右孩子
- 在z的祖父节点左移一次
- 将z的parent和z的兄弟节点交换颜色
查找:
- 就是按照二叉搜索树的查找,不必阐述
删除:
- 先回顾二叉搜索树的删除操作
- 如果删除的节点是z,z没有孩子节点,直接删
- 如果z包含有一个孩子,那么就将z去除掉,让z的这个孩子替代之前z的位置
- 如果z包含两个孩子,我们就去寻找一successory来代替z,然后将y删除,又是一个递归的过程
sucessory的寻找顺序
z右孩子的最左节点
z左孩子的最右节点
举个例子(删除节点中的32)
比44要小,比17要大
发现32右子树是空,如果右子树不为空,就要找左子树,最右边,32的右子树的最左边
删除65
要不就找右子树的左节点,递归去找,要不就找左子树右节点递归找
红黑树的删除操作:
-
就像是普通的搜索二叉树一样删除一个节点z
-
如果z包含右两个孩子,那么拷贝y的值给z的时候,不要复制颜色
-
让y成为需要被删除的那个节点
-
如果y是红色,那么不影响红黑树的属性
-
如果y是黑色的,那么就一定生产了红黑树的冲突
-
假设x是y的那个唯一的孩子节点,x也有可能为空
- 假设x是红色的,直接将x改成黑色即可
- 假设x是黑色的