相信在看这篇文章的时候,你已经清楚普通的二叉树。废话不多说,直接开始!
- 在开始之前,强烈推荐一个网站,https://www.cs.usfca.edu/~galles/visualization/Algorithms.html,这里面具有大量的数据结构,并可以在线演示各种算法过程。(地址是国外的,没有梯子的话访问会比较慢。)
红黑树的性质
-
红黑树是一颗自平衡树,也是一颗二叉树。既然能自平衡,那么在插入和删除的时候,肯定有某种机制在自动调节。红黑树有以下五个特性:
- 性质1:每个节点要么是黑色,要么是红色
- 性质2:根节点是黑色
- 性质3:每个叶子节点(NIL)是黑色
- 性质4:每个红色节点的两个子节点一定是黑色,不能有两个红色节点相连
- 性质5:任意一个节点到每个叶子节点的路径包含数量相同的黑节点,俗称 黑高。
- 延伸性质5.1:从性质5可以推出,如果一个节点存在黑子节点,那么该节点肯定有两个子节点。
-
节点的插入没什么好讲的,今天主要来讲 插入的自平衡 与 删除的自平衡。
红黑树自平衡的三大条件
- 变色:节点的颜色由红变黑或由黑变红
- 左旋:以某个节点为旋转节点,右节点变为旋转节点的父节点,右节点的左子节点变为旋转节点的右子节点
- 右旋:以某个节点为旋转节点,左节点变为旋转节点的父节点,左节点的右子节点变为旋转节点的左子节点
红黑树插入节点的自平衡
讲解平衡操作之前,先约定对应节点的叫法。
- PP 祖父节点,P 父节点,I 插入的节点,S 叔叔节点(后面例子会分左右)
红黑树的插入情况,总共分为以下八种
情景1: 红黑树为空树
- 处理:把插入结点作为根结点,并把结点设置为黑色。
情景2: 插入的结点key已存在
- 处理: 把 I 节点设为当前结点的颜色,更新当前结点的值为插入结点的值
情景3: 插入结点的父节点为黑色节点
- 处理:直接插入。
情景4: 插入结点的父节点为红色节点
- 因为根节点不可能为红色,所以肯定存在祖父节点。
情景4.1: 叔叔节点存在且为红色
- 处理:将P和S设置为黑色,PP设置为红色 && 设置为当前插入结点,然后继续往上遍历,直至红黑树平衡。
- 注意,若 PP 为根节点,是唯一会增加黑色节点的情况。
情景4.2: 叔叔结点不存在或为黑结点,并且插入结点的父亲结点是祖父结点的左子结点
情景4.2.1: 插入结点是其父结点的左子结点
- 处理:将 P设为黑色,PP 设为红色,对PP 进行右旋
情景4.2.2: 插入结点是其父结点的右子结点
- 处理:对P进行右旋 ,把P设置为插入结点,得到情景 4.2.1,进行情景4.2.1 的处理
情景4.3: 叔叔结点不存在或为黑结点,并且插入结点的父亲结点是祖父结点的右子结点
情景4.3.1: 插入结点是其父结点的右子结点
- 处理:将P设为黑色,PP设为红色,对PP进行左旋
情景4.3.2: 插入结点是其父结点的左子结点
- 处理:对P进行右旋,把P设置为插入结点,得到情景4.3.1,进行情景4.3.1的处理
红黑树删除节点的自平衡
- 红黑树删除节点D会出现以下三种情况:
- 1、D节点的左右子树都为空,直接删粗
- 2、D节点只有一个子节点,用子节点替代删除节点。红黑树只有一个子节点的情况下,那么这个必定为红色节点,且没有子节点。 回到情况1。
- 3、D节点有两个子节点,使用后继节点来替换删除节点。后继节点没有左节点,则出现以下两种情况
- 3.1、后继节点没有子节点,回到情况1
- 3.2、后继节点具有右子节点,回到情况2
综上所述,所有的删除情况最终回归情况1。
- 约定节点的名称,如下图所示,灰色代表节点颜色不确定。以下是删除替代节点后的平衡处理。
红黑树删除的情况,分为以下 9 种
情景1: 替换结点是红色结点
- 处理:将替换节点R 与 删除节点 D 交换,将 R 的颜色设置为 D 的颜色,删除 D 即可。
情景2: 替换结点是黑色结点
- 若是黑色节点,根据 黑高 原则,必须进行调整
情景2.1: 替换结点是其父结点的左子结点
情景2.1.1: 替换结点的兄弟结点是红结点
- 即 S 的父节点 P 与 SR、SL 必定为黑色
- 处理:将S设为黑色,P设为红色,对P进行左旋,得到情景2.1.2.3,进行情景2.1.2.3的处理
情景2.1.2: 替换结点的兄弟结点是黑结点
情景2.1.2.1: 替换结点的兄弟结点的右子结点是红结点,左子结点任意颜色
- 处理: 将S的颜色设为P的颜色,P设为黑色,SR设为黑色,对P进行左旋
- 因为 SR 是红色节点,所以 SL 肯定是 NIL 或 红色节点,R 是要删除的节点,则树实际上可以看做已经平衡。
情景2.1.2.2: 替换结点的兄弟结点的右子结点是黑结点,左子结点为红色节点
- 处理:将S设为红色,SL设为黑色,对S进行右旋,得到情景2.1.2.1,进行情景2.1.2.1的处理
情景2.1.2.3: 替换结点的兄弟结点的子结点都为黑结点
- 处理:将S设为红色,把P作为新的替换结点,重新进行删除结点情景处理
情景2.2: 替换结点是其父结点的右子结点
情景2.2.1: 替换结点的兄弟结点是红结点
- 处理:将S设为黑色,P设为红色,对P进行右旋,得到情景2.2.2.3,进行情景2.2.2.3的处理
情景2.2.2: 替换结点的兄弟结点是黑色结点
情景2.2.2.1: 替换结点的兄弟结点的左子结点是红结点,右子结点任意颜色
- 处理:将S的颜色设为P的颜色,P设为黑色,SL设为黑色,对P进行右旋
情景2.2.2.2: 替换结点的兄弟结点的左子结点是黑色结点,右子结点为红色
- 处理:将S设为红色,SR设为黑色,对S进行左旋,得到情景2.2.2.1,进行情景2.2.2.1的处理
情景2.2.2.3: 替换结点的兄弟结点的子结点都是黑色结点
- 处理:将S设为红色,把P作为新的替换结点,重新进行删除结点情景处理