定义:自平衡二叉查找树,每个节点都带有颜色属性,颜色或红色或黑色。
运算限制:1节点是红色或黑色。2根节点是黑色。3每个叶节点(NIL节点,空节点)是黑色的。4每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)。5从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。
基本概念:左旋就是把原节点摘下来,用原节点的右子节点替换原节点,原节点变成右子节点的左子节点,如果原右子节点存在左子节点,则把该左子节点当成原节点的右子节点。右旋就是把原节点摘下来,用原节点的左子节点替换原节点,原节点变成做左子节点的右子节点,如果原左子节点存在右子节点,则把该右子节点当成原节点的左子节点。右旋跟左旋一样,是左旋的逆过程。下面有图。
基本运算:
1,插入。
2,删除 。
3,查找,跟二叉树一样,省略
左旋与右旋
对x左旋得到右图,对y右旋得到左图
看代码,下面代码摘自jdk treemap 类,看解析部分就可以了,下面辅助代码的作用在解析中都说了。
public class RBTree<K, V> implements Tree<K, V> {
private Node<K, V> root;
private static final boolean RED = false;
private static final boolean BLACK = true;
private int size = 0;
private int modCount = 0;
@SuppressWarnings("unchecked")
public V put(K key,V value){
if (key == null) throw new NullPointerException();
//如果跟节点是空,就插入到跟节点
if (root == null){
root = new Node<>();
root.key = key;
root.value = value;
size = 1 ;
modCount ++ ;
return null;
}
//从根节点开始循环,找到插入节点的位置和它的父节点,这里跟二叉查找树是一样的,主要是下面自平衡部分,也就是红黑树优于查找树的原由
Node<K, V> current = root;
Node<K,V> parent;
Comparable<? super K> k = (Comparable<? super K>) key;
int comparaberResult ;
do {
parent = current;
comparaberResult = k.compareTo(current.key);
if (comparaberResult < 0)//小于向左找
current = current.leftChild;
else if (comparaberResult > 0)//大于向右找
current = current.rightChild;
else{
//已经存在这个key,修改key的值
current.value=value;
return value ;
}
//循环直到找到新节点要插入的位置,并找到父节点parent和插入规则comparaberResult
} while (current != null);
//走到这里表示上面的修改没进行,所以是插入新节点
Node<K,V> node = new Node<>();
node.key = key;
node.value = value;
node.parent = parent;
//根据比较结果,知道新节点是左子节点还是右子节点
if (comparaberResult < 0)
parent.leftChild = node;
else
parent.rightChild = node;
//插入之后让树保持平衡
fixAfterInsertion(node);
size++;
modCount++;
return null;
}
private void fixAfterInsertion(Node<K,V> x) {
//默认新节点为红色,以此来调整上层树的平衡
x.color = RED;
//因为红色节点的子节点必须为黑色,所以此处只要父节点是红色就要一直调到变成黑色。
while (x != null && x != root && x.parent.color == RED) {
//不管父节点是左子节点还是右子节点,做的事情都是一样。就是把父节点变成黑色,
//然后把父节点的父节点(父父节点)变成红色去找违反规则的节点,相当于父父节点是一个新插入的红色节点,循环
//如果父节点是左子节点
if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {
Node<K,V> y = rightOf(parentOf(parentOf(x)));
//而且右子节点也是红色,那我同时把两个红色变成黑色,两边黑色节点的数量还是相等的,父节点变成红色,再进循环判断是否需要修改上面节点的颜色。
if (colorOf(y) == RED) {
setColor(parentOf(x), BLACK);
setColor(y, BLACK);
setColor(parentOf(parentOf(x)), RED);
x = parentOf(parentOf(x));
//右子节点是黑色,如果此时我只把左子节点变成黑色,相当于左边新加了一个黑色,那左右两边黑色就不相等了,为了达到第一种情况,
//这个时候如果新加的节点是左子节点,我们只需要先把他的父节点变成黑色,把父父节点变成红色,然后右旋,
//结果为新加的黑色放到了父父节点,右子节点新加红色,左子节点为新加的红色节点,变成了第一种情况。ok
} else {
//由于我们整体要向右旋,如果新节点是右子节点,
//那么在整体右旋结束后,新节点会变成右子节点的左子节点,而我们预期的结果是第一种情况,也就是左右都是红色,
//所以在此之前,我们要先把新加右节点变成加左节点,由于新加节点和它的父节点都是红色,所以直接用父节点左旋就可以了
if (x == rightOf(parentOf(x))) {
//x取父节点左旋
x = parentOf(x);
//左旋完成后,x变成了左子节点
//左旋就是把原节点摘下来,用原节点的右子节点替换原节点,原节点变成右子节点的左子节点,
//如果原右子节点存在左子节点,则把该左子节点当成原节点的右子节点
rotateLeft(x);
}
setColor(parentOf(x), BLACK);
setColor(parentOf(parentOf(x)), RED);
//右旋完成后,变成了上面左右子节点都是红色的情况。循环
//右旋跟上面左旋一样,是左旋的逆过程
//把原节点摘下来,用原节点的左子节点替换原节点,原节点变成做左子节点的右子节点
//如果原左子节点存在右子节点,则把该右子节点当成原节点的左子节点
rotateRight(parentOf(parentOf(x)));
}
} else {
Node<K,V> y = leftOf(parentOf(parentOf(x)));
if (colorOf(y) == RED) {
setColor(parentOf(x), BLACK);
setColor(y, BLACK);
setColor(parentOf(parentOf(x)), RED);
x = parentOf(parentOf(x));
} else {
if (x == leftOf(parentOf(x))) {
x = parentOf(x);
rotateRight(x);
}
setColor(parentOf(x), BLACK);
setColor(parentOf(parentOf(x)), RED);
rotateLeft(parentOf(parentOf(x)));
}
}
}
root.color = BLACK;
}
//删除节点跟二叉树一样的,只是多了调整结构的部分,跟插入一样的原理
public V remove(Object key) {
Node<K,V> p = getNode(key);
if (p == null)
return null;
V oldValue = p.value;
deleteNode(p);
return oldValue;
}
final Node<K,V> getNode(Object key) {
if (key == null) throw new NullPointerException();
@SuppressWarnings("unchecked")
Comparable<? super K> k = (Comparable<? super K>) key;
Node<K,V> p = root;
while (p != null) {
int cmp = k.compareTo(p.key);
if (cmp < 0)
p = p.leftChild;
else if (cmp > 0)
p = p.rightChild;
else
return p;
}
return null;
}
private void deleteNode(Node<K,V> p) {
modCount++;
size--;
//先处理有两个子节点的情况
if (p.leftChild != null && p.rightChild != null) {
Node<K,V> s = successor(p);//进到t.rightChild != null条件语句里面得到右子节点的最左子节点s
p.key = s.key;
p.value = s.value;
p = s;
}
Node<K,V> replacement = (p.leftChild != null ? p.leftChild : p.rightChild);
if (replacement != null) {
replacement.parent = p.parent;
if (p.parent == null)
root = replacement;
else if (p == p.parent.leftChild)
p.parent.leftChild = replacement;
else
p.parent.rightChild = replacement;
p.leftChild = p.rightChild = p.parent = null;
if (p.color == BLACK)
fixAfterDeletion(replacement);
} else if (p.parent == null) {
root = null;
} else {
if (p.color == BLACK)
fixAfterDeletion(p);
if (p.parent != null) {
if (p == p.parent.leftChild)
p.parent.leftChild = null;
else if (p == p.parent.rightChild)
p.parent.rightChild = null;
p.parent = null;
}
}
}
static <K,V> RBTree.Node<K,V> successor(Node<K,V> t) {
if (t == null)
return null;
else if (t.rightChild != null) {
Node<K,V> p = t.rightChild;
while (p.leftChild != null)
p = p.leftChild;
return p;
} else {
Node<K,V> p = t.parent;
Node<K,V> ch = t;
while (p != null && ch == p.rightChild) {
ch = p;
p = p.parent;
}
return p;
}
}
private void fixAfterDeletion(Node<K,V> x) {
while (x != root && colorOf(x) == BLACK) {
if (x == leftOf(parentOf(x))) {
Node<K,V> sib = rightOf(parentOf(x));
if (colorOf(sib) == RED) {
setColor(sib, BLACK);
setColor(parentOf(x), RED);
rotateLeft(parentOf(x));
sib = rightOf(parentOf(x));
}
if (colorOf(leftOf(sib)) == BLACK &&
colorOf(rightOf(sib)) == BLACK) {
setColor(sib, RED);
x = parentOf(x);
} else {
if (colorOf(rightOf(sib)) == BLACK) {
setColor(leftOf(sib), BLACK);
setColor(sib, RED);
rotateRight(sib);
sib = rightOf(parentOf(x));
}
setColor(sib, colorOf(parentOf(x)));
setColor(parentOf(x), BLACK);
setColor(rightOf(sib), BLACK);
rotateLeft(parentOf(x));
x = root;
}
} else {
Node<K,V> sib = leftOf(parentOf(x));
if (colorOf(sib) == RED) {
setColor(sib, BLACK);
setColor(parentOf(x), RED);
rotateRight(parentOf(x));
sib = leftOf(parentOf(x));
}
if (colorOf(rightOf(sib)) == BLACK &&
colorOf(leftOf(sib)) == BLACK) {
setColor(sib, RED);
x = parentOf(x);
} else {
if (colorOf(leftOf(sib)) == BLACK) {
setColor(rightOf(sib), BLACK);
setColor(sib, RED);
rotateLeft(sib);
sib = leftOf(parentOf(x));
}
setColor(sib, colorOf(parentOf(x)));
setColor(parentOf(x), BLACK);
setColor(leftOf(sib), BLACK);
rotateRight(parentOf(x));
x = root;
}
}
}
setColor(x, BLACK);
}
private static <K,V> boolean colorOf(Node<K,V> p) {
return (p == null ? BLACK : p.color);
}
private static <K,V> Node<K,V> parentOf(Node<K,V> p) {
return (p == null ? null: p.parent);
}
private static <K,V> void setColor(Node<K,V> p, boolean c) {
if (p != null)
p.color = c;
}
private static <K,V> Node<K,V> leftOf(Node<K,V> p) {
return (p == null) ? null: p.leftChild;
}
private static <K,V> Node<K,V> rightOf(Node<K,V> p) {
return (p == null) ? null: p.rightChild;
}
/** From CLR */
private void rotateLeft(Node<K,V> p) {
if (p != null) {
Node<K,V> r = p.rightChild;
p.rightChild = r.leftChild;
if (r.leftChild != null)
r.leftChild.parent = p;
r.parent = p.parent;
if (p.parent == null)
root = r;
else if (p.parent.leftChild == p)
p.parent.leftChild = r;
else
p.parent.rightChild = r;
r.leftChild = p;
p.parent = r;
}
}
/** From CLR */
private void rotateRight(Node<K,V> p) {
if (p != null) {
Node<K,V> l = p.leftChild;
p.leftChild = l.rightChild;
if (l.rightChild != null) l.rightChild.parent = p;
l.parent = p.parent;
if (p.parent == null)
root = l;
else if (p.parent.rightChild == p)
p.parent.rightChild = l;
else p.parent.leftChild = l;
l.rightChild = p;
p.parent = l;
}
}
static class Node<K, V> {
K key;
V value;
Node<K, V> leftChild;
Node<K, V> rightChild;
Node<K, V> parent;
boolean color = BLACK;
}
public Node<K, V> getRoot() {
return root;
}
public void setRoot(Node<K, V> root) {
this.root = root;
}
}