目录
插入总结:通过对以上源码的解读,我们可以得出:
删除总结:通过对上面源码的解读,我们可以得出:
注:在开始阅读此文章之前,是默认读者掌握了节点的旋转规则,如果对旋转规则不了解的同学,可以先看我的这篇博客
我把删除和插入节点用xmind进行了总结,上传到了此博客
一、简介
红黑树 (Red Black Tree) 是一种二叉查找树,是在计算机科学中用到的一种数据结构,典型的用途是实现关联数组。
它是在1972年由 Rudolf Bayer 发明的,当时被称为平衡二叉B树 (symmetric binary B-trees)。后来,在1978年被 Leo J. Guibas 和 Robert Sedgewick 修改为如今的“红黑树”。
红黑树和其他二叉查找树类似,都是在进行插入和删除操作时通过特定操作保持二叉查找树的性质,从而获得较高的查找性能。
它虽然是复杂的,但它的最坏情况运行时间也是非常良好的,并且在实践中是高效的:它可以在 O(log n) 时间内做查找,插入和删除,这里的 n 是树中元素的数目。
——百度百科
二、实现思路
在Java中很多对象比如TreeMap,HashMap(1.8)以及Linux虚拟内存的管理,都使用了红黑树的数据结构
想要理解红黑树,需要先知道红黑树是什么?它有什么特点?
红黑树是一种含有红黑结点并能自平衡的二叉查找树。
它必须满足下面性质:
- 性质1:每个节点要么是黑色,要么是红色。
- 性质2:根节点是黑色。
- 性质3:每个叶子节点(NIL)是黑色。
- 性质4:每个红色结点的两个子结点一定都是黑色。
- 性质5:任意一结点到每个叶子结点的路径都包含数量相同的黑结点。
这里我通过TreeMap的源码来和大家一起理解这个神秘的红黑树
2.1 插入节点
/**
* Associates the specified value with the specified key in this map.
* If the map previously contained a mapping for the key, the old
* value is replaced.
*
* @param key key with which the specified value is to be associated
* @param value value to be associated with the specified key
*
* @return the previous value associated with {@code key}, or
* {@code null} if there was no mapping for {@code key}.
* (A {@code null} return can also indicate that the map
* previously associated {@code null} with {@code key}.)
* @throws ClassCastException if the specified key cannot be compared
* with the keys currently in the map
* @throws NullPointerException if the specified key is null
* and this map uses natural ordering, or its comparator
* does not permit null keys
*/
public V put(K key, V value) {
Entry<K,V> t = root;
if (t == null) {
compare(key, key); // type (and possibly null) check
root = new Entry<>(key, value, null);
size = 1;
modCount++;
return null;
}
int cmp;
Entry<K,V> parent;
// split comparator and comparable paths
Comparator<? super K> cpr = comparator;
// 找到待添加节点的父节点并修改value
if (cpr != null) {
do {
parent = t;
cmp = cpr.compare(key, t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
}
else {
if (key == null)
throw new NullPointerException();
@SuppressWarnings("unchecked")
Comparable<? super K> k = (Comparable<? super K>) key;
do {
parent = t;
cmp = k.compareTo(t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
}
// 创建待添加节点并给其赋予相关的父节点
Entry<K,V> e = new Entry<>(key, value, parent);
// 将创建出来的节点放入合适的位置
if (cmp < 0)
parent.left = e;
else
parent.right = e;
// 平衡红黑树的一系列操作(重点)
fixAfterInsertion(e);
// 树中的条目数
size++;
// 树的结构修改数
modCount++;
return null;
}
/** From CLR */
private void fixAfterInsertion(Entry<K,V> x) {
// 新插入的节点颜色默认为红色
x.color = RED;
// 如果新插入节点的父节点颜色为红色 违反了性质4
while (x != null && x != root && x.parent.color == RED) {
// 如果新插入节点的父节点为其父节点的左子节点时
if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {
// 获取当前插入节点的叔叔节点
Entry<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));
// 如果叔叔节点的颜色为黑色
} else {
// 如果当前插入节点是其父节点的右子节点时
if (x == rightOf(parentOf(x))) {
// 将两节点进行左旋操作
x = parentOf(x);
rotateLeft(x);
}
// 将新插入节点的父节点的颜色设置为黑色
setColor(parentOf(x), BLACK);
// 并将其祖父节点的颜色设置为红色
setColor(parentOf(parentOf(x)), RED);
// 将其祖父节点与其左子节点进行右旋
rotateRight(parentOf(parentOf(x)));
}
// 如果新插入节点的父节点为其父节点的右子节点时
} else {
// 找到其叔叔节点
Entry<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;
}
/** From CLR */
private void rotateLeft(Entry<K,V> p) {
if (p != null) {
// 选中新插入的节点
Entry<K,V> r = p.right;
// 将其父节点的右子节点赋值为新插入节点的左子节点
p.right = r.left;
if (r.left != null)
// 将新插入节点的左子节点的父节点设置为新插入节点的父节点
r.left.parent = p;
// 将新插入节点的父节点设置为祖父节点
r.parent = p.parent;
// 判断当前祖父节点是否为根节点
if (p.parent == null)
// 将根节点设置为新插入的节点
root = r;
// 如果当前祖父节点的左子节点是其新插入节点的父节点
else if (p.parent.left == p)
// 将当前祖父节点的左子节点设置为新插入的节点
p.parent.left = r;
else
// 将当前祖父节点的右子节点设置为新插入的节点
p.parent.right = r;
// 将当前新插入节点的左子节点设置为其父节点
r.left = p;
// 将旋转后父节点的父节点设置为当前新插入的节点
p.parent = r;
}
}
/** From CLR */
// 操作方式与左旋相同,方向不一样而已
private void rotateRight(Entry<K,V> p) {
if (p != null) {
Entry<K,V> l = p.left;
p.left = l.right;
if (l.right != null) l.right.parent = p;
l.parent = p.parent;
if (p.parent == null)
root = l;
else if (p.parent.right == p)
p.parent.right = l;
else p.parent.left = l;
l.right = p;
p.parent = l;
}
}
通过对以上源码的解读,我们可以得出:
新插入的节点颜色默认为红色
如果新插入节点的父节点颜色为红色 违反了性质4
1.新插入节点的父节点为其父节点的左子节点时,找到其叔叔节点
1.1 如果叔叔节点的颜色为红色时
1.1.1 将插入节点的父节点和叔叔节点的颜色设置为黑色,并且将插入节点的祖父节点的颜色设置为红色,再将祖父节点设置为插入的节点
1.2 如果叔叔节点的颜色为黑色时
1.2.1 如果当前插入节点是其父节点的右子节点时,先将新插入节点和其父节点进行左旋操作,再进行1.2.2操作
1.2.2 将新插入节点的父节点的颜色设置为黑色,并将其祖父节点的颜色设置为红色,最后将其祖父节点与其左子节点进行右旋
2.新插入节点的父节点为其父节点的右子节点时,找到其叔叔节点
2.1 如果当前叔叔节点为红色
2.1.1 将新插入节点的父节点和其叔叔节点设置为黑色,并将其祖父节点设置为红色,最后将祖父节点设置为新插入的节点
2.2 如果叔叔节点的颜色为黑色时
2.2.1 如果当前插入节点为其父节点的左子节点 ,先将新插入节点和其父节点进行右旋操作。再进行2.2.2操作
2.2.2 将新插入节点的父节点的颜色设置为黑色,并将其祖父节点的颜色设置为红色,最后将其祖父节点与其左子节点进行左旋
3. 最后设置根节点的颜色为黑色
2.2 删除节点
/**
* Delete node p, and then rebalance the tree.
*/
private void deleteEntry(Entry<K,V> p) {
modCount++;
size--;
// If strictly internal, copy successor's element to p and then make p
// point to successor.
// 当前待删除的节点有两个子节点
if (p.left != null && p.right != null) {
// 找到当前节点的前驱或者后继子节点,当前方法采用后继
Entry<K,V> s = successor(p);
// 使用后继子节点替换掉当前待删除的节点
p.key = s.key;
p.value = s.value;
p = s;
} // p has 2 children
// Start fixup at replacement node, if it exists.
// 找到待删除节点的子节点,可能为null
Entry<K,V> replacement = (p.left != null ? p.left : p.right);
// 如果找到子节点
if (replacement != null) {
// Link replacement to parent
// 将当前子节点的父节点指向待删除结点的父节点
replacement.parent = p.parent;
// 如果待删除结点的父节点为空,说明待删除结点为根节点
if (p.parent == null)
// 将根节点替换为当前子节点
root = replacement;
// 如果当前待删除的节点是其父节点的左子节点
else if (p == p.parent.left)
// 将父节点的左子节点替换为待删除节点的子节点 换句话说就是孩子抢了父亲的位置
p.parent.left = replacement;
else
// 如果待删除的节点是其父节点的右子节点,则将父节点的右子节点替换为待删除节点的子节点
p.parent.right = replacement;
// Null out links so they are OK to use by fixAfterDeletion.
// 空出待删除节点的所有链接,以便后续操作
p.left = p.right = p.parent = null;
// Fix replacement
// 如果待删除的节点的颜色为黑色,违反了性质5
if (p.color == BLACK)
// 传入其子节点
fixAfterDeletion(replacement);
// 如果待删除节点的父节点为null,说明为根节点,并且没有子节点,则删除当前树
} else if (p.parent == null) { // return if we are the only node.
root = null;
// 如果待删除节点的父节点不为null,且没有子节点
} else { // No children. Use self as phantom replacement and unlink.
// 如果当前待删除结点的颜色为黑色,违反性质5,则需要做平衡操作
if (p.color == BLACK)
fixAfterDeletion(p);
// 从待删除结点的父节点上删除该节点 (从父亲的角度上清除父子关系)
if (p.parent != null) {
if (p == p.parent.left)
p.parent.left = null;
else if (p == p.parent.right)
p.parent.right = null;
// 将待删除结点的父节点连接删除 (从孩子的角度上清除父子关系)
p.parent = null;
}
}
}
/**
* Returns the successor of the specified Entry, or null if no such.
*/
static <K,V> TreeMap.Entry<K,V> successor(Entry<K,V> t) {
if (t == null)
return null;
// 返回当前节点的后继节点
else if (t.right != null) {
Entry<K,V> p = t.right;
while (p.left != null)
p = p.left;
return p;
// 当前节点没有右子节点,返回null
} else {
Entry<K,V> p = t.parent;
Entry<K,V> ch = t;
// 当前节点不为根节点且为其父节点的右子节点,则返回当前节点的父节点
while (p != null && ch == p.right) {
ch = p;
p = p.parent;
}
return p;
}
}
/** From CLR */
private void fixAfterDeletion(Entry<K,V> x) {
// 当前节点不是根节点,且颜色为黑色
while (x != root && colorOf(x) == BLACK) {
// 如果当前节点是其父节点的左子节点
if (x == leftOf(parentOf(x))) {
// 找到其兄弟节点
Entry<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));
}
// 将当前兄弟节点的颜色设置为x的父节点的颜色
setColor(sib, colorOf(parentOf(x)));
// 将其父节点的颜色设置为黑色
setColor(parentOf(x), BLACK);
// 将当前兄弟节点的右子节点的颜色设置为黑色
setColor(rightOf(sib), BLACK);
// 左旋父节点
rotateLeft(parentOf(x));
// 将当前节点设置为根节点 跳出循环
x = root;
}
// 如果当前节点是其父节点的右子节点
} else { // symmetric
// 找到当前节点的兄弟节点
Entry<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);
}
删除节点相对于插入节点来说比较复杂,不过没关系,掌握了插入的情况下学删除是比较容易的。换汤不换药
通过对上面源码的解读,我们可以得出:
1. 待删除的节点有两个子节点
1.1 找到当前待删除节点的前驱或者后继子节点(当前方法采用后继),并且使用后继子节点替换掉当前待删除的节点,最后再删除后继子节点,转到2
2.待删除的节点有一个子节点
2.1 如果待删除的节点的颜色为红色,用其子节点替换掉待删除的节点
2.2 如果待删除的节点的颜色为黑色,并且其子节点为红色,用当前子节点替换掉待删除的节点然后将颜色改为黑色
2.3 如果待删除的节点的颜色为黑色,并且其子节点为黑色,找到当前子节点的兄弟节点
2.3.1 如果当前兄弟节点是其父节点的右子节点
2.3.1.1 如果当前兄弟节点的颜色为红色,则将当前兄弟节点的颜色设置为黑色,父节点设置为红色,以父节点为中心左旋两节点并且将兄弟节点重新赋值为旋转后的父节点的右子节点
2.3.1.2 如果当前兄弟节点的左右节点的子节点均为黑色,则将当前兄弟节点的颜色设置为红色,并且将当前子节点指向父节点
2.3.1.3 如果当前兄弟节点只有其右子节点为黑色,则将当前兄弟节点的左子节点赋值为黑色,并且将当前兄弟节点的颜色设置为红色,再右旋当前兄弟节点,最后将兄弟节点重新赋值为旋转后节点,再进行2.3.1.4 操作
2.3.1.4 将当前兄弟节点的颜色设置为其父节点的颜色,并将其父节点的颜色设置为黑色,然后将当前兄弟节点的右子节点的颜色设置为黑色,再以其父节点为中心左旋两节点,最后将当前节点设置为根节点,以便跳出循环
2.3.2 如果当前兄弟节点是其父节点的左子节点
2.3.2.1 如果当前兄弟节点的颜色为红色,则将当前兄弟节点的颜色设置为黑色,父节点设置为红色,以父节点为中心右旋两节点并且将兄弟节点重新赋值为旋转后的父节点的左子节点
2.3.2.2 如果当前兄弟节点的左右节点的子节点均为黑色,则将当前兄弟节点的颜色设置为红色,并且将当前子节点指向父节点
2.3.2.3 如果当前兄弟节点只有其左子节点为黑色,将当前兄弟节点的右子节点赋值为黑色,并且将当前兄弟节点的颜色设置为红色,再左旋当前兄弟节点,最后将兄弟节点重新赋值为旋转后节点,再进行2.3.2.4操作
2.3.2.4 将当前兄弟节点的颜色设置为其父节点的颜色,并将其父节点的颜色设置为黑色,然后将当前兄弟节点的左子节点的颜色设置为黑色,再以其父节点为中心右旋两节点,最后将当前节点设置为根节点(跳出循环)
3.待删除的节点没有子节点
3.1 待删除的节点为红色,直接删除
3.2 待删除的节点为黑色,将当前待删除的节点作为平衡条件进行以上操作,再删除该节点
4.将当前节点的颜色设置为黑色
图片我就不画了,如果大家觉得没图片不太好理解的话,我推荐这篇博客
三、代码仿现
我是通过模仿TreeMap来实现红黑树,里边没有任何注释
大家可以自行解读来检验自己有没有掌握
@AllArgsConstructor
@NoArgsConstructor
@Data
@ToString
public class RedBlackNode {
public Integer key;
public Integer value;
public RedBlackNode leftNode;
public RedBlackNode rightNode;
public RedBlackNode parentNode;
public String color;
@Override
public String toString() {
JSONObject jsonObject = new JSONObject();
jsonObject.put("key",this.key);
jsonObject.put("value",this.value);
jsonObject.put("leftNode",this.leftNode);
jsonObject.put("rightNode",this.rightNode);
jsonObject.put("parentNode",this.parentNode);
jsonObject.put("color",this.color);
return jsonObject.toJSONString();
}
}
/**
* @Author: Eating melons the masses
* @Date: 2020/3/15 15:42
*/
public class RedBlackTree {
public static final String BLACK = "black";
public static final String RED = "red";
public RedBlackNode root;
public RedBlackNode insert(Integer key,Integer value){
RedBlackNode thisNode = root;
if (root == null){
root = new RedBlackNode(key,value,null,null,null,BLACK);
return root;
}
int cmp;
RedBlackNode parent = thisNode;
RedBlackNode current = thisNode;
while (current != null){
parent = current;
int cos = compass(parent.key,key);
if (cos > 0){
current = current.leftNode;
}else if (cos < 0){
current = current.rightNode;
}else {
current.setValue(value);
return current;
}
}
RedBlackNode redBlackNode = new RedBlackNode(key, value, null, null, parent, RED);
cmp = compass(parent.key,key);
if (cmp > 0){
parent.leftNode = redBlackNode;
}else {
parent.rightNode = redBlackNode;
}
addNodeToTree(redBlackNode);
return root;
}
public RedBlackNode delete(int key){
RedBlackNode redBlackNode = findNodeByKey(key);
if (redBlackNode.leftNode != null && redBlackNode.rightNode != null){
RedBlackNode minNode = minNode(redBlackNode.rightNode);
redBlackNode.key = minNode.key;
redBlackNode.value = minNode.value;
redBlackNode = minNode;
}
RedBlackNode onlyChild = redBlackNode.leftNode == null ? redBlackNode.rightNode : redBlackNode.leftNode;
if (onlyChild != null){
onlyChild.parentNode = redBlackNode.parentNode;
if (redBlackNode.parentNode == null){
root = onlyChild;
}else if (redBlackNode == redBlackNode.parentNode.leftNode){
redBlackNode.parentNode.leftNode = onlyChild;
}else {
redBlackNode.parentNode.rightNode = onlyChild;
}
redBlackNode.leftNode = redBlackNode.parentNode = redBlackNode.rightNode = null;
if (redBlackNode.color == BLACK){
deleteNodeByTree(onlyChild);
}
}else if (redBlackNode.parentNode == null){
root = null;
}else {
if (redBlackNode.color == BLACK){
deleteNodeByTree(redBlackNode);
}
if (redBlackNode.parentNode != null){
if (redBlackNode == redBlackNode.parentNode.leftNode){
redBlackNode.parentNode.leftNode = null;
}else {
redBlackNode.parentNode.rightNode = null;
}
redBlackNode.parentNode = null;
}
}
return root;
}
private void deleteNodeByTree(RedBlackNode child) {
while (child != root && child.color == BLACK){
if (child == child.parentNode.leftNode){
RedBlackNode broNode = child.parentNode.rightNode;
if (broNode.color == RED){
broNode.setColor(BLACK);
child.parentNode.setColor(RED);
ll_rotate(child.parentNode);
broNode = child.parentNode.rightNode;
}else if (broNode.leftNode.color == BLACK &&
broNode.rightNode.color == BLACK){
broNode.setColor(RED);
child = child.parentNode;
}else {
if (broNode.rightNode.color == BLACK){
broNode.leftNode.setColor(BLACK);
rr_rotate(broNode);
broNode = child.parentNode.rightNode;
}
broNode.setColor(child.parentNode.color);
child.parentNode.setColor(BLACK);
broNode.rightNode.setColor(BLACK);
ll_rotate(child.parentNode);
child = root;
}
}else {
RedBlackNode broNode = child.parentNode.leftNode;
if (broNode.color == RED){
broNode.setColor(BLACK);
child.parentNode.setColor(RED);
rr_rotate(child.parentNode);
broNode = child.parentNode.leftNode;
}else if (broNode.leftNode.color == BLACK &&
broNode.rightNode.color == BLACK){
broNode.setColor(RED);
child = child.parentNode;
}else {
if (broNode.leftNode.color == BLACK){
broNode.rightNode.setColor(BLACK);
ll_rotate(broNode);
broNode = child.parentNode.leftNode;
}
broNode.setColor(child.parentNode.color);
child.parentNode.setColor(BLACK);
broNode.leftNode.setColor(BLACK);
rr_rotate(child.parentNode);
child = root;
}
}
}
child.setColor(BLACK);
}
private RedBlackNode minNode(RedBlackNode node) {
if (node != null){
RedBlackNode current = node;
while (current != null){
if (current.leftNode != null){
current = current.leftNode;
}else {
return current;
}
}
}
return null;
}
private RedBlackNode findNodeByKey(int key) {
if (root != null){
RedBlackNode current = root;
while (current != null){
if (current.key > key){
current = current.leftNode;
}else if (current.key < key){
current = current.rightNode;
}else {
return current;
}
}
}
return null;
}
private void addNodeToTree(RedBlackNode redBlackNode) {
if (redBlackNode != null && redBlackNode.parentNode.color == RED){
RedBlackNode uncle = null;
RedBlackNode grandparent = redBlackNode.parentNode.parentNode;
if (grandparent != null){
if (redBlackNode.parentNode == grandparent.leftNode){
uncle = redBlackNode.parentNode.parentNode.rightNode;
String color = uncle == null?BLACK:uncle.color;
if (color == RED){
redBlackNode.parentNode.setColor(BLACK);
uncle.setColor(BLACK);
grandparent.setColor(RED);
redBlackNode = grandparent;
}else {
if (redBlackNode == redBlackNode.parentNode.rightNode){
ll_rotate(redBlackNode.parentNode);
}
redBlackNode.parentNode.setColor(BLACK);
grandparent.setColor(RED);
rr_rotate(grandparent);
}
}else {
uncle = redBlackNode.parentNode.parentNode.leftNode;
String color = uncle == null?BLACK:uncle.color;
if (color == RED){
redBlackNode.parentNode.setColor(BLACK);
uncle.setColor(BLACK);
grandparent.setColor(RED);
redBlackNode = grandparent;
}else {
if (redBlackNode == redBlackNode.parentNode.leftNode){
rr_rotate(redBlackNode.parentNode);
}
redBlackNode.parentNode.setColor(BLACK);
grandparent.setColor(RED);
ll_rotate(grandparent);
}
}
}
}
root.setColor(BLACK);
}
private void rr_rotate(RedBlackNode node) {
if (node != null){
RedBlackNode leftNode = node.leftNode;
node.leftNode = leftNode.rightNode;
if (leftNode.rightNode != null){
leftNode.rightNode.parentNode = node;
}
leftNode.parentNode = node.parentNode;
if (node.parentNode == null){
root = leftNode;
}else if (node.parentNode.leftNode == node){
node.parentNode.leftNode = leftNode;
}else {
node.parentNode.rightNode = leftNode;
}
leftNode.rightNode = node;
node.parentNode = leftNode;
}
}
private int compass(Integer le, Integer ri) {
return le - ri;
}
private void ll_rotate(RedBlackNode node) {
if (node != null){
RedBlackNode rightNode = node.rightNode;
node.rightNode = rightNode.leftNode;
if (rightNode.leftNode != null){
rightNode.leftNode.parentNode = node;
}
rightNode.parentNode = node.parentNode;
if (node.parentNode == null){
root = rightNode;
}else if (node.parentNode.leftNode == node){
node.parentNode.leftNode = rightNode;
}else {
node.parentNode.rightNode = rightNode;
}
rightNode.leftNode = node;
node.parentNode = rightNode;
}
}
public static void main(String[] args) {
RedBlackTree redBlackTree = new RedBlackTree();
redBlackTree.insert(18,12);
redBlackTree.insert(8,134);
redBlackTree.insert(3,325);
redBlackTree.insert(9,5464);
redBlackTree.insert(10,1);
redBlackTree.insert(5,32);
redBlackTree.insert(4,122);
redBlackTree.insert(1,25);
redBlackTree.insert(7,65);
redBlackTree.insert(13,123);
redBlackTree.insert(12, 1455);
redBlackTree.insert(21, 342);
redBlackTree.insert(22, 534);
redBlackTree.delete(5);
redBlackTree.delete(7);
System.out.println(redBlackTree.root);
}
}
{\__/} {\__/}
( ·-·) (·-· )
/ >------------------------------------------------< \
| ☆ |
| ☆ |
| ★ |
| ☆ |
| ☆ |
| |
-------------------------------------