红黑树的性质
1,每个节点非黑即红。
2,根节点是黑色的。
3,叶节点(NIL)是黑色的。
4,红节点的两个孩子都是黑色的。
5,对每个节点,从该节点到其所有后代的简单路径上,均包含了同样数目的黑节点。
旋转
为了维持红黑树的性质,要改变某些节点的颜色和指针结构,旋转改变了指针结构。
左旋:以x和y之间的链为“支轴”进行的,使得x的右孩子为y的左孩子,y的父节点为x的父节点,y的左孩子为x。
代码:
template <class T>
void RedBlackTree<T>::left_rotate(RedBlackTreeNode<T> *pnode)
{
RedBlackTreeNode<T>* rightnode = pnode->right;
pnode->right = rightnode->left;`
if(rightnode->left != NIL)
rightnode->left->parent = pnode;
rightnode->parent = pnode->parent;
if(pnode->parent == NIL)
root = rightnode;
else if(pnode == pnode->parent->left)
pnode->parent->left = rightnode;
else
pnode->parent->right = rightnode;
rightnode->left = pnode;
pnode->parent = rightnode;
}
插入
每次插入节点,至多只有一个性质性质被破坏,性质2或者4
如果是性质2,则将根节点变为黑色即可。
违反性质4,必定因为它和它的父亲都为红色,则其祖父节点必为黑色。此时根据父亲是祖父的左孩子还是右孩子进行讨论,左右之间是对称的,书中只给出了左孩子的三种情况。
情况1: z的叔叔结点y是红色的
将祖父染为红色,父亲和叔叔染为黑色,将祖父变成判定点,一直向上循环判断。
情况2:z的叔叔y是黑色的,而且z是右孩子
情况3:z的叔叔y是黑色的,而且z是左孩子
情况2可以通过旋转变为情况3.之后,将父亲染成黑色,祖父染成红色,再从祖父处进行右旋转。过程中不会对其他红黑树性质造成破坏。
删除
删除过程与二叉查找树一样,分为三种情况
<1>无左右孩子、<2>有左孩子或者右孩子、<3>既有树=左孩子又有右孩子。
但删除后还得检查是否破坏红黑树性质。
如果删除的是黑节点,会破坏红黑树性质。
违反性质的三种情况:
1:若删除的是根节点,唯一子节点为红色,则根节点变成红色,违反了性质2.
2:若被删节点的唯一孩子和父亲都是红色,性质4被破坏.
3:被删节点会导致包含该点的路径的黑节点树-1,违反了性质5.
额外一重黑色:
顶替被删节点的节点还有一重额外的黑色,此时可能违背了性质1(红+黑),但在这种假设下,性质5成立。节点额外的黑色是针对X节点的,不是反映在color属性上的。
函数修复性质1,2,4:
性质2、4很简单,因为X为红色,所以将X变为黑色即可。
性质1:函数的目的是将额外的黑色沿树上移,直到:
X指向红黑节点,将x着为黑色。
X指向根节点。
执行适当的旋转和重新着色,退出循环。
注意
X总是指向具有双重黑色的非根节点。
w不可能是T.nil
性质5交换前后不变
四种情况:
情况1:x的兄弟w是红色的
此时因为x是双重黑色,贡献两个黑色结点,所有w必有黑色孩子。此时将w着为黑色,父亲着为红色,在对父亲做一次左旋转。此时x的新兄弟w是黑色,这样将情况1转换为情况2、3或4。
情况2:x的兄弟w是黑色的,而且w的两个孩子都是黑色的。
处理过程是从x和w上去掉一重黑色,即x只有一重黑色而w着为红色,给x的父节点添加额外黑色。
情况3:x的兄弟w是黑色的,w的左孩子是红色的,右孩子是黑色的
交换w和其左孩子的颜色,并对w进行右旋转。旋转后x的新兄弟w是一个有红色右孩子的黑结点,转换成了情况4。
情况4:x的兄弟w是黑色的,而且w的右孩子是红色的。
执行过程是将w的颜色设置为父亲的颜色,将父亲的颜色设置为黑色,将w的右孩子着为黑色,然后在父亲做一次右旋,最后将x设置为根root。
1.1
8
4 12
2 6 10 14
1 3 5 7 9 11 13 15
8
4(红) 12(红)
2 6 10 14
1 3 5 7 9 11 13 15
8
4(红) 12(红)
2 6 10 14
1 3 5 7 9 11 13 15 (全红)
1.2
不是,违反了性质4,。不是,违反了性质5。
1.3
是
1.4
此时的叶节点深度为黑高度
1.5
红节点的数目<=黑节点数,全为黑节点的路径为红黑相等路径的一半
1.6
2^2k-1 2^k-1
1.7
2:1
0