红黑树的插入
在一棵AVL树中,我们通过左旋和右旋来调整由于插入和删除所造成的不平衡问题。在红黑树中,可以使用两种方式进行平衡操作:
1. 重新着色
2. 旋转
旋转操作是二叉搜索树调整平衡的最好方法,因为不会打乱节点排列顺序,右旋操作,将左子树借一个节点给右子树,左旋操作,将右子树借一个节点给左子树,又因为红黑树有颜色的区分,也可以说是借颜色,为了保持红黑树黑色节点在路径上总和数量的相等。
当红黑树中出现不平衡的状态,我们首先会考虑重新着色,如果重新着色依旧不能使红黑树平衡,那么就考虑旋转。插入操作主要有两种情况,具体取决于叔叔结点的颜色。如果叔叔结点是红色的,我们会重新着色。如果叔叔结点是黑色的,我们会旋转或者重新着色,或者两者都考虑。
一个 NULL 结点被认为是黑色的,这在上篇已经提到过。
设 x 为新插入的结点,x节点设置为红色。
进行标准的 BST 插入并将新插入的结点设置为红色。
1.如果 x 的父结点 p 是黑色并且 x 不是根结点
2.如果 x 是根结点,将 x 的颜色转化为黑色(整棵树的黑高增加 1)。
3.如果 x 的父结点 p 是红色并且 x 不是根结点,则:
a). 如果 x 的叔叔结点 u 是红色。
将插入结点 x 的父结点(Parent )p 和叔叔(uncle)结点 u 的颜色变为黑色;
将 x 的爷爷结点(Grand Parent)g 设置为红色;
将 x = x的爷爷结点 g ,对于新的 x 重复 2,3两步。
b). 如果 x 的叔叔结点 u 是黑色,则对于 x、 x 的父结点 p 和 x 的爷爷结点 g有以下四种情况:
LL(p 是 g 的左孩子且 x 是 p 的左孩子)
LR(p 是 g 的左孩子且 x 是 p 的右孩子)
RR(p 是 g 的右孩子且 x 是 p 的右孩子)
RL(p 是 g 的右孩子且 x 是 p 的左孩子)
情况1
标准的BST插入,插入节点的父节点是黑色,插入节点x本身是红色。那么什么都不需要操作了,满足红黑树性质。
因为x节点父子节点都是黑色的,符合红黑树性质。
情况2
插入节点是根节点,那么将插入节点x设置为黑色,红黑树性质要求根节点需要是黑色。
情况3
如果 x 的父结点 p 是红色并且 x 不是根结点。由于x的父节点是红色,那么说明祖父节点是黑色,因为红色节点不能相邻,所以可以判断叔叔节点的颜色是红色和黑色两种情况,对应如下分为3.1,3.2两种情况:
情况3.1
a) 如果 x 的叔叔结点 u 是红色。
将插入结点 x 的父结点(Parent )p 和叔叔(uncle)结点 u 的颜色变为黑色;
将 x 的爷爷结点(Grand Parent)g 设置为红色;
将 x = x的爷爷结点 g ,对于新的 x 重复 2,3两步。
首先将2,15节点设置成黑色,将6节点设置成红色,插入节点x重新赋值为x的祖父节点6,然后从节点6开始重复2,3的流程。
至于什么时候终止向上递归,那么要取决于插入节点x的所遇到的情况,能不能符合红黑树的性质。
情况3.2
b). 如果 x 的叔叔结点 u 是黑色,则对于 x、 x 的父结点 p 和 x 的爷爷结点 g有以下四种情况:
LL(p 是 g 的左孩子且 x 是 p 的左孩子)
LR(p 是 g 的左孩子且 x 是 p 的右孩子)
RR(p 是 g 的右孩子且 x 是 p 的右孩子)
RL(p 是 g 的右孩子且 x 是 p 的左孩子)
LL
LL(p 是 g 的左孩子且 x 是 p 的左孩子)
左边插入了x节点之后,多出来一个红色节点,需要进行右旋将红色节点借到右边去,因为右边有两个黑色节点,可以容纳更多一个红色节点,但是左边不允许,那么具体的操作就是:1.将祖父节点的颜色和父节点的颜色互换;2.右旋节点祖父节点6。
LR
LR(p 是 g 的左孩子且 x 是 p 的右孩子)
这种情况其实和LL情况差不多,可以将LR情况转化成LL情况之后,在使用LL的操作方式进行红黑树平衡操作。
将2设为新插入的节点X,进行LL操作。
RR
RR(p 是 g 的右孩子且 x 是 p 的右孩子)
操作其实和LL差不多,只不过是对称操作。1.将15节点和6节点的颜色互换;2.节点6左旋。
RL
RL(p 是 g 的右孩子且 x 是 p 的左孩子)
RL节点情况可以转化成RR的情况,先右旋15节点,转化成了RR的情况,根据RR情况进行操作:
操作代码
红黑树结构:
public class TreeNode {
public T value = null;
public TreeNode parent = null;
public TreeNode left = null;
public TreeNode right = null;
public NodeColor color;
public TreeNode(NodeColor color) {
this.color = color;
}
public TreeNode(T value,NodeColor color) {
this.value = value;
this.color = color;
}
}
左右旋操作:
private void rotateLeft(TreeNode subRoot) {
//右节点不为空,才能左旋
if (subRoot.right != null && subRoot.right.value != null) {
TreeNode right = subRoot.right;
TreeNode rl = right.left;
TreeNode parent = subRoot.parent;
if (parent != null) {
if (parent.left == subRoot) {
parent.left = right;
} else if (parent.right == subRoot) {
parent.right = right;
}
}
right.parent = parent;
right.left = subRoot;
subRoot.parent = right;
subRoot.right = rl;
if (rl != null) {
rl.parent = subRoot;
}
if (subRoot == root) {
root = subRoot.parent;
}
}
}
private void rotateRight(TreeNode subRoot) {
//右节点不为空,才能左旋
if (subRoot.left != null && subRoot.left.value != null) {
TreeNode left = subRoot.left;
TreeNode lr = left.right;
TreeNode parent = subRoot.parent;
if (parent != null) {
if (parent.left == subRoot) {
parent.left = left;
} else if (parent.right == subRoot) {
parent.right = left;
}
left.parent = parent;
}
left.right = subRoot;
subRoot.parent = left;
subRoot.left = lr;
if (lr != null) {
lr.parent = subRoot;
}
if (subRoot == root) {
root = subRoot.parent;
}
}
}
BST插入操作:
//常规bst插入操作
TreeNode indexNode = root;
while (indexNode != null && indexNode.value != null) {
if (val.compareTo(indexNode.value) > 0) {
indexNode = indexNode.right;
} else {
indexNode = indexNode.left;
}
}
if (indexNode != null && indexNode.parent != null) {
TreeNode newNode = new TreeNode(val,NodeColor.RED);
//插入的具体实现
insertNodeInner(indexNode,newNode);
//插入后,平衡操作
BalanceTreeForInserted(newNode);
}
平衡操作:
private void BalanceTreeForInserted(TreeNode newNode) {
TreeNode parent = newNode.parent;
if (newNode == root && newNode.parent == null) {
newNode.color = NodeColor.BLACK;
return;
}
//2.1 插入节点父亲节点是黑色,不用调整,结束
if (parent.color == NodeColor.BLACK) {
return;
}
//2.2 插入节点父亲节点是红色,插入后需要调整(父节点是红,那么一定有祖父节点,红节点不能是红色)
if (parent.color == NodeColor.RED){
TreeNode grandParent = parent.parent;
boolean cl = false;
if (parent.left == newNode) {
cl = true;
} else if (parent.right == newNode) {
cl = false;
}
TreeNode uncle = null;
boolean pl = false;
if (grandParent.left == parent) {
uncle = grandParent.right;
pl = true;
} else if (grandParent.right == parent) {
uncle = grandParent.left;
pl = false;
}
if (uncle != null) {
if (uncle.color == NodeColor.RED){
uncle.color = NodeColor.BLACK;
parent.color = NodeColor.BLACK;
grandParent.color = NodeColor.RED;
BalanceTreeForInserted(grandParent);
} else if (uncle.color == NodeColor.BLACK) {
if (pl) { //LL.LR两种情况
if (!cl) {
rotateLeft(parent);
}
grandParent.color = NodeColor.RED;
grandParent.left.color = NodeColor.BLACK;
rotateRight(grandParent);
} else {//RR,RL两种情况
if (cl) {
rotateRight(parent);
}
grandParent.color = NodeColor.RED;
grandParent.right.color = NodeColor.BLACK;
rotateLeft(grandParent);
}
}
}
}
}
总结
模拟红黑树操作的在线网站,强烈推荐:点我