红黑树难点在与对插入及删除几种状态转换的理解。而理解最好的方法莫过于实测。在这里提供一个java实现及UI直观过程。
一,插入三种状态
1.叔叔节点也为红色
2.当前节点是右子和父节点是左子
3.当前节点和父节点都是左子且叔叔节点为空或黑
来一张算法导论上的图:
二、删除四种状态
1.兄弟节点为红色
2.兄弟节点为黑色且兄弟节点的子节点都为黑色
3.兄弟节点为黑色且兄弟节点的左节点为红,右节点为黑
4.兄弟节点为黑色且兄弟节点的右节点为红
再来一张算法导论上的图:
先上效果:
三、java实现
public class Rbtree {
public static class Node {
public Node(int value) {
this.value = value;
this.isRed = true;
}
public boolean isLeft() {
return this.parent.left == this;
}
public boolean isRed;
public Node parent;
public Node left;
public Node right;
public int value;
@Override
public String toString() {
return (isRed ? "red:" : "black:") + value + "";
}
}
public static Node insert(Node root, Node node) {
Node current = root;
for (;;) {
if (node.value > current.value) {
if (current.right == null) {
current.right = node;
node.parent = current;
break;
}
current = current.right;
} else {
if (current.left == null) {
current.left = node;
node.parent = current;
break;
}
current = current.left;
}
}
Node newRoot = fixInsert(node);
if (newRoot != null) {
root = newRoot;
}
return root;
}
private static Node fixInsert(Node node) {
//根节点
if (node.parent == null) {
node.isRed = false;
return node;
}
//父节点为黑直接结束
if (node.isRed && !node.parent.isRed) {
return null;
}
if (node.parent.parent == null) {
node.parent.isRed = false;
return null;
}
if (node.parent.isLeft()) {
//叔叔节点也为红色
if (node.parent.parent.right != null && node.parent.parent.right.isRed) {
node.parent.isRed = false;
node.parent.parent.right.isRed = false;
node.parent.parent.isRed = true;
return fixInsert(node.parent.parent);
}
//当前节点和父节点都是左子且叔叔节点为空或黑(为空就是叶子节点,所以同样认为是黑)
if (node.isLeft()
&&(node.parent.parent.right == null || !node.parent.parent.right.isRed)) {
node.parent.parent.isRed = true;
node.parent.isRed = false;
return rightRotate(node.parent.parent);
//当前节点是右子和父节点是左子
} else {
leftRotate(node.parent);
return fixInsert(node.left);
}
} else {
//叔叔节点也为红色
if (node.parent.parent.left != null && node.parent.parent.left.isRed) {
node.parent.isRed = false;
node.parent.parent.left.isRed = false;
node.parent.parent.isRed = true;
return fixInsert(node.parent.parent);
}
//当前节点和父节点都是右子且叔叔节点为空或黑(为空就是叶子节点,所以同样认为是黑)
if (!node.isLeft()
&&(node.parent.parent.left == null || !node.parent.parent.left.isRed)) {
node.parent.parent.isRed = true;
node.parent.isRed = false;
return leftRotate(node.parent.parent);
//当前节点是左子和父节点是右子
} else {
rightRotate(node.parent);
return fixInsert(node.right);
}
}
}
private static Node leftRotate(Node node) {
if (node.right == null) {
return null;
}
Node r = node.right;
node.right = r.left;
if (node.right != null) {
node.right.parent = node;
}
Node p = node.parent;
r.left = node;
r.parent = p;
if (r.parent != null) {
if (node.isLeft()) {
r.parent.left = r;
} else {
r.parent.right = r;
}
}
node.parent = r;
if (r.parent == null) {
return r;
} else {
return null;
}
}
private static Node rightRotate(Node node) {
if (node.left == null) {
return null;
}
Node l = node.left;
node.left = l.right;
if (node.left != null) {
node.left.parent = node;
}
Node p = node.parent;
l.right = node;
l.parent = p;
if (l.parent != null) {
if (node.isLeft()) {
l.parent.left = l;
} else {
l.parent.right = l;
}
}
node.parent = l;
if (l.parent == null) {
return l;
} else {
return null;
}
}
public static Node delete(Node root, Node node) {
Node current = root;
Node newRoot = null;
for (;;) {
if (current.value == node.value) {
Node replace = findReplaceNode(current);
if (replace != null) {
current.value = replace.value;
current = replace;
}
break;
} else if (current.value < node.value) {
if (current.right == null) {
break;
} else {
current = current.right;
}
} else {
if (current.left == null) {
break;
} else {
current = current.left;
}
}
}
//替换节点只肯存在一个子节点
//左子存在
if (current.left != null) {
//删除根节点
if (current.parent == null) {
newRoot = current.left;
newRoot.parent = null;
} else {
current.value = current.left.value;
//标识该节点需要删除
current.left.value = Integer.MIN_VALUE;
current = current.left;
}
//右子存在
} else if (current.right != null) {
//删除根节点
if (current.parent == null) {
newRoot = current.right;
newRoot.parent = null;
} else {
current.value = current.right.value;
current.right.value = Integer.MIN_VALUE;
current = current.right;
}
} else {
current.value = Integer.MIN_VALUE;
}
if (newRoot==null) {
newRoot = fixDelete(current);
}
if (newRoot != null) {
root = newRoot;
}
return root;
}
private static Node fixDelete(Node node) {
//根节点
if (node.parent == null) {
//所有节点被删除返回空根
if (node.value==Integer.MIN_VALUE) {
return new Node(0);
}else {
node.isRed=false;
return node;
}
}
if (node.isRed) {
//节点为红色时如果节点是被删除节点,直接删除
if (node.value==Integer.MIN_VALUE) {
deleteNode(node);
return null;
//如果不是则涂黑结束
}else {
node.isRed=false;
return null;
}
}
if (node.isLeft()) {
//兄弟节点为红色
if (node.parent.right.isRed) {
node.parent.isRed = true;
node.parent.right.isRed = false;
Node a = leftRotate(node.parent);
Node b = fixDelete(node);
return b!=null?b:a;
//兄弟节点为黑色且兄弟节点的子节点都为黑色(或空)
} else if (!node.parent.right.isRed
&& (node.parent.right.left == null || !node.parent.right.left.isRed)
&& (node.parent.right.right == null || !node.parent.right.right.isRed)) {
node.parent.right.isRed = true;
Node tmp = node.parent;
deleteNode(node);
return fixDelete(tmp);
//兄弟节点为黑色且兄弟节点的左节点为红,右节点为黑(或空)
} else if (!node.parent.right.isRed
&&(node.parent.right.left != null && node.parent.right.left.isRed)
&& (node.parent.right.right == null || !node.parent.right.right.isRed)) {
node.parent.right.left.isRed=false;
node.parent.right.isRed=true;
Node a = rightRotate(node.parent.right);
Node b = fixDelete(node);
return b!=null?b:a;
//兄弟节点为黑色且兄弟节点的右节点为红
}else if(!node.parent.right.isRed
&& (node.parent.right.right != null && node.parent.right.right.isRed)) {
node.parent.right.isRed=node.parent.isRed;
node.parent.right.right.isRed=false;
node.parent.isRed=false;
Node tmp=node.parent;
deleteNode(node);
return leftRotate(tmp);
}
} else {
//兄弟节点为红色
if (node.parent.left.isRed) {
node.parent.isRed = true;
node.parent.left.isRed = false;
Node a = rightRotate(node.parent);
Node b = fixDelete(node);
return b!=null?b:a;
//兄弟节点为黑色且兄弟节点的子节点都为黑色(或空)
} else if (!node.parent.left.isRed
&& (node.parent.left.left == null || !node.parent.left.left.isRed)
&& (node.parent.left.right == null || !node.parent.left.right.isRed)) {
node.parent.left.isRed = true;
Node tmp = node.parent;
deleteNode(node);
return fixDelete(tmp);
//兄弟节点为黑色且兄弟节点的右节点为红,左节点为黑(或空)
} else if (!node.parent.left.isRed
&&(node.parent.left.left == null || !node.parent.left.left.isRed)
&& (node.parent.left.right != null && node.parent.left.right.isRed)) {
node.parent.left.left.isRed=false;
node.parent.left.isRed=true;
Node a = leftRotate(node.parent.left);
Node b = fixDelete(node);
return b!=null?b:a;
//兄弟节点为黑色且兄弟节点的左节点为红
}else if(!node.parent.left.isRed
&& (node.parent.left.left != null && node.parent.left.left.isRed)) {
node.parent.left.isRed=node.parent.isRed;
node.parent.left.left.isRed=false;
node.parent.isRed=false;
Node tmp=node.parent;
deleteNode(node);
return leftRotate(tmp);
}
}
return null;
}
private static void deleteNode(Node node) {
if (node.value == Integer.MIN_VALUE) {
if (node.isLeft()) {
node.parent.left = null;
} else {
node.parent.right = null;
}
node.parent = null;
}
}
private static Node findReplaceNode(Node del) {
Node result = null;
if ((result = del.left) != null) {
while (result.right != null) {
result = result.right;
}
} else if ((result = del.right) != null) {
while (result.left != null) {
result = result.left;
}
}
return result;
}
}
四、动态UI过程java实现
import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.util.Random;
import javax.swing.JFrame;
import com.bc.Rbtree.Node;
public class DrawTree {
private static Node root;
public static void main(String[] args) throws InterruptedException {
Random random = new Random();
Draw draw= new Draw();
root = new Node(50);
draw.paintNodes(root);
for (int i = 0; i < 20; i++) {
root= Rbtree.insert(root, new Node(i));
Thread.sleep(1000);
draw.paintNodes(root);
}
for (int i = 0; i < 10; i++) {
root= Rbtree.delete(root, new Node(i));
Thread.sleep(1000);
draw.paintNodes(root);
System.out.println(i);
}
draw.paintNodes(root);
}
}
class Draw extends JFrame {
private static final long serialVersionUID = 1L;
private static final int w = 1200;
private static final int h = 600;
private static final int ply = 50;
private static final int begin = 50;
private Graphics jg;
private Color rectColor = new Color(0xf5f5f5);
public Draw() {
Container p = getContentPane();
setBounds(50, 50, w, h);
setVisible(true);
p.setBackground(rectColor);
setLayout(null);
setResizable(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jg = this.getGraphics();
}
public void paintNodes(Node node) {
try {
Thread.sleep(100);
jg.clearRect(0, 0, w, h);
paintNode(node ,0,w ,begin);
Thread.sleep(100);
} catch (Exception e) {
e.printStackTrace();
}
}
public void paintNode(Node node ,int xb,int xe ,int y) {
if (node.isRed) {
jg.setColor(Color.RED);
}else {
jg.setColor(Color.BLACK);
}
int x=xb+(xe-xb)/2;
jg.drawOval(x, y, 20, 20);
jg.setColor(Color.BLACK);
jg.drawString(node.value+"", x+2, y+15);
if (node.left!=null) {
jg.drawLine(x, y, xb+(x-xb)/2, y+ply);
paintNode( node.left, xb, x, y+ply);
}
if (node.right!=null) {
jg.drawLine(x, y, x+(xe-x)/2, y+ply);
paintNode( node.right, x, xe, y+ply);
}
}
}
----完工----