红黑树的插入操作
1. 以排序二叉树的方法插入新节点,并将它设置为红色。
设置红色:如果设置黑色,会导致根节点到叶子节点的路径上多出一个额外的黑节点,这样会很难调整。
但是设置为红色可能会导致出现两个连续的红色节点(违反了性质4),因此需要通过颜色转换和树旋转来进行调整。
2. 颜色转换和树旋转
新插入的节点N, N的父亲节点设置为P,P的兄弟节点设置为B,P的附近点设置为G。(可以理解为newnode,parent,brother,grandparent)。
情形1:新节点N是树的根节点(root),设置为黑色即可。情形2:新节点N的父节点P为黑色。此时,新插入的节点P为红色,不违反红黑树的各性质。
情形3:父节点P和父节点的兄弟节点B都是红色的。
分析:插入之后破坏了性质4(两个连续的红色节点),所以如图的调整。但是此时新插入节点的父节点的父节点G改变了颜色,那么此时G.color 与 G.parent.color之间的关系就是新的问题所在,所以循环中下一次迭代将G作为新的输入。
这张图相当于在P和N之间做了一个旋转。
情形4:父节点P是红色的,而其兄弟节点B是黑色或者缺少。这里将插入的节点分为左右子节点讨论,其实没有什么区别。
分析:如第二张图,插入的节点是其根结点的右节点,破坏了性质5:一个节点向下到叶子节点的简单路径上的黑色节点数相同。所以进行了一次旋转,状态就和第一张图相似,但是此时破坏了性质4:连续两个红节点,且兄弟节点B为黑色,所以旋转维持性质4.
以上是父节点P作为左子节点,如果是右子节点的情况和这个类似,只是选择的旋转方向不同,这里就不做分析了。
参考代码:
public void add(T data) {
// 如果根节点为空
if(root == null){
root = new Node(data, null, null, null);
}
else{
Node current = root;
Node parent = null;
int cmp = 0;
//搜索到合适的叶子节点,以该节点为父节点添加新的节点
while(current != null){//找到合适的位置 假定的"null"会被我指定的值替换
parent = current;
cmp = data.compareTo(current.data);
if(cmp < 0){
current = current.left;
}
else{
current = current.right;
}
}
//创建新节点, 通过直接的比较知道了它的父节点的值, 接下来就是通过比较 判断是他父节点的 左还是右节点
Node newNode = new Node(data, parent, null, null);
if(cmp > 0){
parent.right = newNode;
}
else{
parent.left = newNode;
}
rbInsert_Fixup(newNode);
}
}
//维护红黑树性质
private void rbInsert_Fixup(Node newNode){
newNode.color = RED;
//直到这个新节点的父节点不是根,且newNode的父节点不是红色
while(newNode != null && newNode != root && newNode.parent.color == RED){
//如果newNode的父节点是其父节点的左节点
if(parentOf(newNode) == leftOf(parentOf(parentOf(newNode)))){
//获取newNode的父节点的兄弟节点
Node y = rightOf(parentOf(parentOf(newNode)));
//如果它的父节点的兄弟节点是红色
if(colorOf(y) == RED){
//将newNode的父节点设为黑色
setColor(parentOf(newNode), BLACK);
//将newNode的父节点的兄弟节点设为黑色
setColor(y, BLACK);
//将newNode的父节点的父节点染成红色
setColor(parentOf(parentOf(newNode)), RED);
newNode = parentOf(parentOf(newNode));
}
//如果newNode的父节点的兄弟节点是黑色
else{
//如果newNode是其父节点的右节点
if(newNode == rightOf(parentOf(newNode))){
//获取newNode的父节点设为newNode
newNode = parentOf(newNode);
rotateLeft(newNode);
}
//将newNode的父节点设为黑色
setColor(parentOf(newNode), BLACK);
//将newNode的父节点的父节点染成红色
setColor(parentOf(parentOf(newNode)), RED);
rotateRight(parentOf(parentOf(newNode)));
}
}
//如果newNode 的父节点是其父节点的右节点
else{
//获取newNode的父节点的兄弟节点
Node y = leftOf(parentOf(parentOf(newNode)));
//如果它的父节点的兄弟节点是红色
if(colorOf(y) == RED){
//将newNode的父节点设为黑色
setColor(parentOf(newNode), BLACK);
//将newNode的父节点的兄弟节点设为黑色
setColor(y, BLACK);
//将newNode的父节点的父节点染成红色
setColor(parentOf(parentOf(newNode)), RED);
newNode = parentOf(parentOf(newNode));
}
//如果newNode的父节点的兄弟节点是黑色
else{
//如果newNode是其父节点的右节点
if(newNode == leftOf(parentOf(newNode))){
//获取newNode的父节点设为newNode
newNode = parentOf(newNode);
rotateRight(newNode);
}
//将newNode的父节点设为黑色
setColor(parentOf(newNode), BLACK);
//将newNode的父节点的父节点染成红色
setColor(parentOf(parentOf(newNode)), RED);
rotateLeft(parentOf(parentOf(newNode)));
}
}
}
//将根节点设为黑色
root.color = BLACK;
}
可参考:点击打开链接中对各性质的描述。
以上就是这篇的主要内容。欢迎指出错误和不足之处,谢谢!