红黑树是一棵二叉搜索树,它在每个结点上增加了一个存储位来表示结点颜色(RED或BLACK)。通过对任何一条从根到叶子的简单路径上各个节点的颜色进行约束,红黑树确保没有一条路径会比其他路径长出2倍,因而是近似于平衡的。
树中每个结点包含5个属性:color,key,left,right和p。
一棵红黑树是满足下面红黑性质的二叉搜索树:
1.每个节点或是红色的,或是黑色的。
2.根节点是黑色的。
3.每个叶结点(NIL)是黑色的。
4.如果一个结点是红色的,则它的两个子结点都是黑色的。
5.对每个结点,从该结点到其所有后代叶结点的简单路径上
均包含相同数目的黑色结点。
旋转:
指针结构的修改是通过旋转(ratation)来完成的,这是一种能保持二叉搜索树性质的搜索树局部操作。
左旋和右旋: <<<-------------- LEFT_ROTATE()
| |
Y X
/ \ / \
X C A Y
/ \ / \
A B B C
------------------->>>RIGHT_ROTATE()
无论是左旋和右旋转换之后存储规律都没有变,这样操作的结果可以改变树的高度和修改红黑树属性。
插入:
我们可以在O(lgn)时间内完成向一棵含n个结点的红黑树中插入一个新节点。参见搜索二叉树的插入。需要修改的是将结点着为红色。
为了保持红黑树的性质用RBINSERT_FIXUP来对结点重新着色并旋转。
关于RB_INSERT_FIXUP:
如果插入的是根结点,由于原树是空树,此情况只会违反性质2,因此直接把此结点涂为黑色;
如果插入的结点的父结点是黑色,由于此不会违反性质2和性质4,红黑树没有被破坏,所以此时什么也不做。
但当遇到下述3种情况时又该如何调整呢?
● 插入修复情况1:如果当前结点的父结点是红色且祖父结点的另一个子结点(叔叔结点)是红色
● 插入修复情况2:当前节点的父节点是红色,叔叔节点是黑色,当前节点是其父节点的右子
● 插入修复情况3:当前节点的父节点是红色,叔叔节点是黑色,当前节点是其父节点的左子
伪代码:
while z.p.color == RED
if z.p == z.p.p.left
y = z.p.p.right
if y.color == RED
z.p.color == BLACK
y.color == BLACK
z.p.p.color == RED
z=z.p.p //结点指针上移
else
if z==z.p.right
z = z.p
LEFT-ROTATE(T,z)
z.p.color = BLACK //case3
z.p.p.color = RED //case3
RIGHT-ROTATE(T,z.p.p) //case3
else if()
...//左右互换
T.root.color = BLACK