黑树属于平衡二叉树。它不严格是因为它不是严格控制左、右子树高度或节点数之差小于等于1,但红黑树高度依然是平均log(n),且最坏情况高度不会超过2log(n)。
红黑树(red-black tree) 是一棵满足下述性质的二叉查找树:
1. 每一个结点要么是红色,要么是黑色。
2. 根结点是黑色的。
3. 所有叶子结点都是黑色的(实际上都是Null指针,下图用NIL表示)。叶子结点不包含任何关键字信息,所有查询关键字都在非终结点上。
4. 每个红色结点的两个子节点必须是黑色的。换句话说:从每个叶子到根的所有路径上不能有两个连续的红色结点
5. 从任一结点到其每个叶子的所有路径都包含相同数目的黑色结点
红黑树的优势
红黑树能够以O(log2(N))的时间复杂度进行搜索、插入、删除操作。此外,任何不平衡都会在3次旋转之内解决。这一点是AVL所不具备的。
什么时候使用红黑树
相比AVL树而言,红黑树没有严格定义左右子树高度差值,并不严格意义的平衡。如果要涉及到很多插入、删除,用AVL的话会很多次旋转(rotation),此时红黑树是更好的选择。反之,查询多,更改少,即静态的话AVL是更好的选择。在查询效率上,由于AVL树严格平衡,AVL树会比红黑树略快,但时间复杂度是要给数量级上的。此外,相比较AVL树而言,红黑树需要额外的O(n)的空间来存储颜色。
红黑树插入的4种情形
1)没有root节点。处理:将该节点直接设置为黑色节点
2)有根节点,且父节点是黑色处理:直接插入无需处理
3) 父亲节点与叔叔节点同为红色。处理:
a换色:将父亲与叔叔的节点同时更改为黑色。将祖父节点设置为红色。
b检查:检查祖父节点是否满足(每两个连续的节点不能是红色,根节点不能是红色)
4)父节点是红色,叔节点是黑色时,又分如下四种情况:
a当前节点是父亲的左孩子,父亲是祖父的左孩子。【ll】处理:a将祖父节点右旋;b交换父节点和祖父节点的颜色
b当前节点是父亲的右孩子,父亲是祖父的右孩子。【rr】处理:a将祖父节点左旋b交换父节点与祖父节点的颜色
c当前节点是父亲的右孩子,父亲是祖父的左孩子。【rl】处理:a将父节点左旋,并将父节点作为当前节点;b再使用ll
d当前节点是父亲的左孩子,父亲是祖父的右孩子。【lr】处理:a将父节点右旋,并将父节点作为当前节点;b使用rr
总结为:一线处理:左就右旋,右就左旋。交换父亲与祖父的颜色
三角处理:左就右旋,右就左旋。交给一线处理。
红黑树删除的情形
情况①:如果X没有孩子,且如果X是红色,直接删除X;如果X是黑色,则以X为当前节点进行旋转调色,最后删掉X
情况②:如果X只有一个孩子C,交换X和C的数值,再对新X进行删除。根据红黑树特性,此时X不可能为红色,因为红色节点要么没有孩子,要么有两个黑孩子。此时以新X为当前节点进行情况①的判断
情况③:如果X有两个孩子,则从后继中找到最小节点D,交换X和D的数值,再对新X进行删除。此时以新X为当前节点进行情况①或②的判断
节点可能有0个子节点、1个子节点、2个子节点,再加上节点可分为红色节点和黑色节点,因此总共有6种节点。
a. 黑色节点,没子节点。
b. 黑色节点,1个红色节点。
c. 黑色节点,2个子节点。
d. 红色节点,没子节点。
e. 红色节点,1个子节点。
f. 红色节点,2个子节点。
但是,在红黑树中,e情况不可能出现,因为要使父节点变为红色,只能通过颜色反转来实现。
b情况中,该子节点只能是红色,否则不满足性质5。
删除处理
1.节点有两个子节点的时候
先讨论情况c和f,即节点有两个子节点。
假设要删除节点X,按照二叉搜索树的删除方法,寻找X的后驱继承节点Y。然后除了颜色不变之外,互换X和Y的位置。此时X节点只有一个或没有节点,继续删除它。
假设要删除节点4,则节点5是节点4的后驱继承者。(节点4的右节点中的最小节点。)交换节点5和4,节点颜色不变,
继续删除X。此时X是没有子节点的黑色节点,适用于情况a(a. 黑色节点,没子节点。)的删除
2.节点是红色,且没有子节点
要讨论的是情况 d. 红色节点,没子节点。直接删除即可
3.节点是黑色,且只有一个红色节点
讨论的是情况b
现在要删除节点2。节点2有一个红色节点,直接删除节点2,节点1补上节点2的位置,并且节点1的颜色变为黑色
4.节点是黑色的,且没有子节点