红黑树(二)
一.插入
插入的所有结点默认是红色。插入结点称为默认结点
1.变色:
条件:父亲结点是红色,叔叔结点是红色
操作:
(1)父亲结点变成黑色。
(2)叔叔结点变成黑色。
(3)爷爷结点变成红色。
(4)当前结点设为爷爷。
2.旋转
条件:当前父结点是红色,叔叔是黑色,当前结点是右子树。
操作:以父结点左旋,当前结点设为父结点。
条件:当前父结点是红色,叔叔是黑色,当前结点是左字数。
操作:
(1)父亲结点变成黑色
(2)把爷爷结点变成红色
(3)以爷爷结点右旋
3.代码
首先来颗红黑树:
假设我们需要插入一个元素:值是19。
这时候就不满足红黑树的一些性质了,出现两个连在一起的红结点。需要进行一些变色和旋转操作。
首先:创建一个结点类。
并将上一篇帖子写的左旋和右旋操作对应的方法放入结点类中。
原文链接:https://blog.csdn.net/leno_scholar/article/details/106426806
public class Node {
private final int Red = 0;
private final int Black =1;
public int data; //存的数字
int color = Red; //颜色
Node left; //左子树
Node right; //右字数
Node parent; //父节点
//左旋
//以形参node做为根旋转。
public void leftRotate(Node node){
if(node.parent == null){
Node A = node; //根节点
Node B = A.right; //根节点的右节点
//移动三部曲:动B的左节点
//第一步
B.left.parent = A;
//第二部:动B节点
B.left = A;
B.parent = null;
//三部曲:动A节点
A.parent = B;
A.right = B.left;
}
}
//右旋
//以形参node做为根旋转。
public void rightRotate(Node node){
if(node.parent == null){
Node A = node;
Node S = node.left;
//移动三部曲:动B的右节点
//一部曲
B.right.parent = A;
//二部曲:动B节点
B.right = A;
B.parent = null;
//三部曲:动A节点
A.parent = B;
A.left = B.right;
}
}
}
为了便于区分,将插入方法单独展示(插入方法仍放与Node类中):
这个方法就是对中序二叉树的插入方法。多个判断是否达成红黑树性质。
/*
将这棵树的根结点作为参数传入,value是需要插入的值。
当然,这个value可以是对象、引用,甚至可以是另一棵红黑树(有点3D红黑树的味道)。
*/
public void inser(Node root,int data){
if(root.data < data){
if(root.right == null){
root.right = new Node(data);
isRedAndBlackTree(root.right); //判断插入后这颗红黑树是否平衡
}else{
inser(root.right, data);
}
}else{
if(root.left == null){
root.left = new Node(data);
isRedAndBlackTree(root.left); //判断插入后这颗红黑树是否平衡
}else{
inser(root.left, data);
}
}
}
接下来单独写这个isRedAndBlackTree()方法,这也是重点。
public void isRedAndBlackTree(Node node){
Node grandParent = node.parent.parent; //找到当前结点的爷爷结点。
//下面开始判断是否需要变色。红0,黑1
if( (grandParent.left.color == 0) && (grandParent.right.color == 0) ){
//叔叔和父亲一起变黑。
grandParent.left.color = Black;
grandParent.right.color = Black;
//爷爷变红
grandParent.color = Black;
}
node = grandParent;//把爷爷节点设为当前节点。
grandParent = node.parent.parent; //刷新爷爷(自己变成了爷爷,需要新爷爷)
Node uncle; //找叔叔()
if(grandParent.left == node.parent){ //如果爷爷的左孩子是自己的爸爸,那叔叔就是爷爷的右孩子
uncle = grandParent.right;
}else
uncle = grandParent.left; //反之,取反。
//开始判断是否需要旋转
if( (uncle.color == 1) && (node.parent.color == 0)){
if(node == node.parent.right){ //如果是右子树
leftRotate(node.parent); //左旋
node = node.left; //更新当前结点,当前结点设为旋转的根结点。
//接着右旋爷爷节点
grandParent = node.parent.parent; //更新爷爷
if(grandParent.left == node.parent){ /更新叔叔
uncle = grandParent.right;
}else
uncle = grandParent.left;
//开始判断是否需要二次旋转。
if(node.parent.color == 0 && uncle.color == 1){
node.parent.color = Black;
grandParent.color = Red;
rightRotate(grandParent);
}
}else{ //如果是左子树,右旋
node.parent.color = Black; //右旋比左旋多两步。
node.parent.parent.color = Black;
rightRotate(node.parent.parent);
node = node.parent.right; //将当前结点设为旋转的根结点
//更新爷爷和叔叔
grandParent = node.parent.parent;
if(grandParent.left == node.parent){
uncle = grandParent.right;
}else
uncle = grandParent.left;
//判断是否需要二次旋转。
if(node.parent.color == 0 && uncle.color == 1){
node.parent.color = Black;
grandParent.color = Red;
leftRotate(grandParent);
}
}
}
}
欢迎大佬纠正。