最近看了数据结构的红黑树,感觉其丝毫不比B树简单。对于删除和插入操作,网上的各种博文也看了不少,讲的大都很详细,但没有详细的变化过程。个人觉得掌握红黑树的删除和插入照着一个例子的详细过程对着规则看是比较容易的方法,故自己画了一下,传了上来。自后附上了自己的java源码。
红黑树的基础性质就跳过了。
首先看插入,我们把插入的节点都染成红色,因为如果然后黑色插入会导致该路径的黑高度比其他路径大一,这是很难调整的一个性质。插入红色的节点后,如果父节点也是红色,就会违反性质,我们需要调整。一共是6种情况,考虑左右对称的话,其实只有三种情况。
case1:
如果新插入的节点B与的父节点A是红色,并且叔父节点D也是红色,那么爷爷节点C肯定是黑色,这样的话,直接重新涂色,并使爷爷节点C成为新的X节点,进行下一次判断,因为可能把C节点涂红后C的父节点是红色。
case2:
如果插入节点B的叔父节点是黑色,并且B与父节点,爷爷节点,成“Z"形不在同一条直线上,那么对A左旋转,并将x指向x的父节点,旋转后x指针是下移了一层。因为A,B都是红色,所以不会旋转不会破坏黑高度,并将情况转为成了case3.
case3:
到了这步,就应该笑了,这肯定是最后一次变化。我们只需对x的祖父节点右旋转就大功告成了。
我们以插入3,4,1,6,8,-1,7为例。下面是我手画的图上传上来。
相比插入,删除就复杂了一些。
算法的思想如下:设要删除的节点为t,真实删除的节点为y。如果t是叶节点或者t只有右子女,那么y就是t;如果t有左子女或者有双子女,那么y就是t的前驱节点(注:前驱节点就是大于等于t的最小节点)。然后把y与t的值交换,再从树中删除y节点。从过程中我们看到,破坏红黑树的性质是在删除y节点中。如果y是红色,则不破坏红黑树的性质。下面需要分几种情况考虑y是黑色的情况。我们先定义x是y的子节点,w是x的兄弟节点。
case1:y是黑色,w是红色.
因为w是红色,则x,w的共同父节点一定是黑色。这是不好解决的,不好解决的大都通过颜色变化,旋转变化,变成容易解决的。这里主要是A的黑高度比D那边少1,我们将w染成黑色,父节点染成红色,然后对B节点左旋,这时候两边黑高度就相同。这时候还没有结束,因为一开始C的高度就比A大1,然后,C与A的父节点都是B,黑高度还是不平衡,所以还要继续。
case2:y是黑色,w是黑色,且两个子女都是黑色.
把w染成红色,这时候如果B是红色,染黑,那么两边高度平衡,就解决了。否则让x指向B,进行下次循环。
case3:y是黑色,w是黑色,且左子女红色有子女黑色
这时候我们把c然后红色,D染成黑色,右旋转D,变成了第四种情况。
case4:y是黑色,w是黑色,且左子女可黑可红,右子女是红色
做旋转B,D保持为B的颜色,D两个子女都设为黑色,那么左子女的高度增加了1,高度平衡,结束。
下面附上源代码
package tree;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.Random;
public class RedBlackTree {
private TreeNode root;
private static final TreeNode NIL;
static {
NIL = new TreeNode(-1, Color.black);
}
public void insert(int data) {
if (root == null) {
root = new TreeNode(data, Color.black);
return;
}
TreeNode parent = null;
TreeNode temp = root;
while (temp != NIL) {
parent = temp;
if (data >= temp.key) {
temp = temp.right;
} else if (data < temp.key) {
temp = temp.left;
}
}
if (data < parent.key) {
parent.left = new TreeNode(data, Color.red, parent);
temp = parent.left;
} else {
parent.right = new TreeNode(data, Color.red, parent);
temp = parent.right;
}
fixInsert(temp);
}
private void fixInsert(TreeNode node) {
while (node.parent != null && node.parent.color == Color.red) {
TreeNode parent = node.parent;
TreeNode grandParent = parent.parent;
if (parent == grandParent.right) {
TreeNode uncle = grandParent.left;
// 叔父也为红色,重新着色即可
if (uncle.color == Color.red) {
grandParent.color = Color.red;
uncle.color = Color.black;
parent.color = Color.black;
// node 上移
node = grandParent;
} else {
// 同一条直线上,旋转
if (node == parent.right) {
parent.color = Color.black;
grandParent.color = Color.red;
leftRotate(grandParent);
}
// 成z形,旋转
else {
rightRotate(parent);
node = node.right;
}
}
} else {
TreeNode uncle = grandParent.right;
if (uncle.color == Color.red) {
grandParent.color = Color.red;
uncle.color = Color.black;
parent.color = Color.black;
node = grandParent;
} else {
if (node == parent.left) {
parent.color = Color.black;
grandParent.color = Color.red;
rightRotate(grandParent);
} else {
leftRotate(parent);
node = node.left;
}
}
}
}
root.color = Color.black;
}
private void rightRotate(TreeNode node) {
TreeNode parent = node.parent;
TreeNode child = node.left;
if (parent != null) {
if (parent.right == node) {
// 有3个节点的父节点指针要改
parent.right = child;
} else {
parent.left = child;
}
child.parent = parent;
}
node.left = child.right;
child.right.parent = node;
child.right = node;
node.parent = child;
if (parent == null){
root = child;
root.parent = null;
}
}
private void leftRotate(TreeNode node) {
TreeNode parent = node.parent;
TreeNode child = node.right;
if (parent != null) {
if (parent.right == node) {
// 有3个节点的父节点指针要改
parent.right = child;
} else {
parent.left = child;
}
child.parent = parent;
}
node.right = child.left;
child.left.parent = node;
child.left = node;
node.parent = child;
if (parent == null){
root = child;
root.parent = null;
}
}
public void inorder() {
if(root == null){
System.out.println("empty tree!");
return;
}
inorder(root);
}
private void inorder(TreeNode node) {
if (node == NIL)
return;
inorder(node.left);
visit(node);
inorder(node.right);
}
private void visit(TreeNode node) {
if (node == null || node == NIL)
return;
System.out.print("["+node.color + "," + node.key+"]");
}
public void delete(int data) {
if (root == null) {
System.out.println("empty tree!");
return;
}
TreeNode findNode = root;
while (findNode != NIL && findNode.key != data) {
if (data > findNode.key)
findNode = findNode.right;
else
findNode = findNode.left;
}
// 未找到
if (findNode == NIL)
return;
TreeNode deleteNode = NIL;
if (findNode.left == NIL || findNode.right == NIL) {
deleteNode = findNode;
} else {
deleteNode = successor(findNode);
if(deleteNode == null) deleteNode = findNode;
}
TreeNode x = NIL;
if (deleteNode.left != NIL)
x = deleteNode.left;
else
x = deleteNode.right;
x.parent = deleteNode.parent;
// 要删除的是根节点
if (deleteNode == root) {
root = x;
if (root.left ==null && root.right == null) {
root = null;
return;
}
} else {
if (deleteNode == deleteNode.parent.left) {
deleteNode.parent.left = x;
} else {
deleteNode.parent.right = x;
}
}
findNode.key = deleteNode.key;
if (deleteNode.color == Color.black) {
deleteFix(x);
}
}
private void deleteFix(TreeNode x) {
while (x.color == Color.black && x != root) {
if (x == x.parent.left) {
TreeNode brother = x.parent.right;
if (brother.color == Color.red) {
brother.color = Color.black;
x.parent.color = Color.red;
TreeNode temp = x.parent;
leftRotate(x.parent);
x.parent = temp;// 这两行主要是修复旋转可能改变NIL的父节点
brother = x.parent.right;
} else {// 兄弟颜色是黑色
if (brother.left.color == Color.black
&& brother.right.color == Color.black) {
brother.color = Color.red;
x = x.parent;
} else if (brother.left.color == Color.red
&& brother.right.color == Color.black) {
// 兄弟节点左红右黑
brother.color = Color.red;
brother.left.color = Color.black;
TreeNode temp = x.parent;
rightRotate(brother);
x.parent = temp;// 这两行主要是修复旋转可能改变NIL的父节点
brother = x.parent.right;
} else {// 兄弟节点右红
brother.color = x.parent.color;
x.parent.color = Color.black;
brother.right.color = Color.black;
leftRotate(brother.parent);
x = root;
}
}
} else {
TreeNode brother = x.parent.left;
if (brother.color == Color.red) {
brother.color = Color.black;
x.parent.color = Color.red;
TreeNode temp = x.parent;
rightRotate(x.parent);
x.parent = temp;// 这两行主要是修复旋转可能改变NIL的父节点
brother = x.parent.left;
} else {// 兄弟颜色是黑色
if (brother.right.color == Color.black
&& brother.left.color == Color.black) {
brother.color = Color.red;
x = x.parent;
} else if (brother.right.color == Color.red
&& brother.left.color == Color.black) {
// 兄弟节点左红右黑
brother.color = Color.red;
brother.right.color = Color.black;
TreeNode temp = x.parent;
leftRotate(brother);
x.parent = temp;// 这两行主要是修复旋转可能改变NIL的父节点
brother = x.parent.left;
} else {// 兄弟节点右红
brother.color = x.parent.color;
x.parent.color = Color.black;
brother.left.color = Color.black;
rightRotate(brother.parent);
x = root;
}
}
}
}
x.color = Color.black;
}
private void testInsert(int[] keys) {
for (int i = 0; i < keys.length; ++i){
insert(keys[i]);
}
}
private void testDelete(int[] keys) {
for (int i = 0; i < keys.length; ++i) {
delete(keys[i]);
}
}
public static void main(String[] args) {
RedBlackTree tree = new RedBlackTree();
Random random = new Random(System.currentTimeMillis());
List<Integer> list = new ArrayList<Integer>();
for(int i=0;i<10000;++i){
int key = random.nextInt(100000);
list.add(key);
}
System.out.println(list);
for(int i=0;i<list.size();++i){
tree.insert(list.get(i));
}
for(int i=0;i<list.size();++i){
tree.delete(list.get(i));
}
tree.inorder();
System.out.println("\n-------------------------");
tree.bfs();
}
private TreeNode successor(TreeNode node) {
if (node.right != NIL) {
node = node.right;
while (node.left != NIL)
node = node.left;
return node;
}
TreeNode parent = node.parent;
while ((parent != null) && (node == parent.right)) {
node = parent;
parent = node.parent;
}
if (parent == null)
return null;
else
return parent;
}
public void bfs() {
if(root == null){
System.out.println("empty tree");
return;
}
Queue<TreeNode> queue = new ArrayDeque<RedBlackTree.TreeNode>();
queue.add(root);
while (!queue.isEmpty()) {
TreeNode node = queue.peek();
queue.remove();
visit(node);
if (node.left != NIL)
queue.add(node.left);
if (node.right != NIL)
queue.add(node.right);
}
}
static class TreeNode {
Color color;
TreeNode left;
TreeNode right;
TreeNode parent;
int key;
public TreeNode(int data, Color color) {
this.key = data;
this.color = color;
left = NIL;
right = NIL;
parent = null;
}
public TreeNode(int data, Color color, TreeNode parent) {
this(data, color);
this.parent = parent;
}
boolean isLeaf() {
if (left == NIL && right == NIL )
return true;
return false;
}
}
static enum Color {
red, black
}
}