1、基本概念
红黑树是二叉查找树的一种,与平衡查找树类似,但红黑树的平衡性不像平衡树那样严格。
红黑树的特点:
- 任何一个节点都有颜色,黑色或者红色
- 根节点是黑色的
- 父子节点之间不能出现两个连续的红节点
- 任何一个节点向下遍历到其子孙的叶子节点,所经过的黑节点个数必须相等
- 空节点被认为是黑色的
红黑树的基本操作插入、删除、遍历。内容操作和平衡树一样,左右旋转。
public class Test {
private static Node root;
private static final boolean RED = false;
private static final boolean BLACK = true;
static class Node{
int data;
Node left;
Node right;
Node parent;
boolean color;
public Node(int data) {
this.data = data;
this.color = BLACK;
}
}
public static void main(String[] args) {
int[] src = { 10, 40, 30, 60, 90, 70, 20, 50, 80 };
for (int i = 0; i < src.length; i++)
insert(src[i]);
midTrav(root);
System.out.println("\n-----------------------------------");
Node node = searchNode(root, 30);
System.out.println(node.data+"");
remove(node);
midTrav(root);
System.out.println("\n-----------------------------------");
}
/*
* px px
* / /
* x y
* / \ --(左旋)-. / \
* lx y x ry
* / \ / \
* ly ry lx ly
* */
private static void leftRotate(Node x) {
Node y = x.right;
// 将 “y的左孩子” 设为 “x的右孩子”;
x.right = y.left;
if(y.left != null)
//将ly的父节点指向x
y.left.parent = x;
//将y的父节点指向px
y.parent = x.parent;
//为y指定父节点
if(x.parent == null)
root = y;//x的父节点为空 表示x为根节点
else
//如果x为左子树,则让y也为左子树
if(x.parent.left == x)
y.parent.left = y;
else
//如果x为右子树,则让y也为右子树
y.parent.right = y;
//将x的父节点指向y
y.left = x;
x.parent = y;
}
/*
* 对红黑树的节点(y)进行右旋转
*
* 右旋示意图(对节点y进行左旋):
* py py
* / /
* y x
* / \ --(右旋)-. / \
* x ry lx y
* / \ / \
* lx rx rx ry
*
*/
private static void rightRotate(Node y) {
Node x = y.left;
y.left = x.right;
if (x.right != null)
x.right.parent = y;
x.parent = y.parent;
if (y.parent == null) {
root = x;
} else {
if (y == y.parent.right)
y.parent.right = x;
else
y.parent.left = x;
}
x.right = y;
y.parent = x;
}
private static void remove(Node node) {
Node child, parent;
boolean color;
// 被删除节点的"左右孩子都不为空"的情况。
if ( (node.left!=null) && (node.right!=null) ) {
// 被删节点的后继节点。(称为"取代节点")
// 用它来取代"被删节点"的位置,然后再将"被删节点"去掉。
Node replace = node;
// 获取后继节点
replace = replace.right;
while (replace.left != null)
replace = replace.left;
// "node节点"不是根节点(只有根节点不存在父节点)
if (node.parent!=null) {
if (node.parent.left == node)
node.parent.left = replace;
else
node.parent.right = replace;
} else {
// "node节点"是根节点,更新根节点。
root = replace;
}
// child是"取代节点"的右孩子,也是需要"调整的节点"。
// "取代节点"肯定不存在左孩子!因为它是一个后继节点。
child = replace.right;
parent = replace.parent;
// 保存"取代节点"的颜色
color = replace.color;
// "被删除节点"是"它的后继节点的父节点"
if (parent == node) {
parent = replace;
} else {
// child不为空
if (child!=null)
child.parent = parent;
parent.left = child;
replace.right = node.right;
node.right.parent = replace;
}
replace.parent = node.parent;
replace.color = node.color;
replace.left = node.left;
node.left.parent = replace;
if (color == BLACK)
removeFixUp(child, parent);
node = null;
return ;
}
if (node.left !=null) {
child = node.left;
} else {
child = node.right;
}
parent = node.parent;
// 保存"取代节点"的颜色
color = node.color;
if (child!=null)
child.parent = parent;
// "node节点"不是根节点
if (parent!=null) {
if (parent.left == node)
parent.left = child;
else
parent.right = child;
} else {
root = child;
}
if (color == BLACK)
removeFixUp(child, parent);
node = null;
}
private static void removeFixUp(Node node, Node parent) {
Node other;
while ((node==null || node.color==BLACK) && (node != root)) {
if (parent.left == node) {
other = parent.right;
if (other.color == RED) {
// Case 1: x的兄弟w是红色的
other.color = BLACK;
parent.color = RED;
leftRotate(parent);
other = parent.right;
}
if ((other.left==null || other.left.color==BLACK) &&
(other.right==null || other.right.color==BLACK)) {
// Case 2: x的兄弟w是黑色,且w的俩个孩子也都是黑色的
other.color = RED;
node = parent;
parent = node.parent;
} else {
if (other.right==null || other.right.color==BLACK) {
// Case 3: x的兄弟w是黑色的,并且w的左孩子是红色,右孩子为黑色。
other.left.color = BLACK;
other.color = RED;
rightRotate(other);
other = parent.right;
}
// Case 4: x的兄弟w是黑色的;并且w的右孩子是红色的,左孩子任意颜色。
other.color = parent.color;
parent.color = BLACK;
other.right.color = BLACK;
leftRotate(parent);
node = root;
break;
}
} else {
other = parent.left;
if (other.color == RED) {
// Case 1: x的兄弟w是红色的
other.color = BLACK;
parent.color = RED;
rightRotate(parent);
other = parent.left;
}
if ((other.left==null || other.left.color==BLACK) &&
(other.right==null || other.right.color==BLACK)) {
// Case 2: x的兄弟w是黑色,且w的俩个孩子也都是黑色的
other.color = RED;
node = parent;
parent = node.parent;
} else {
if (other.left==null || other.left.color==BLACK) {
// Case 3: x的兄弟w是黑色的,并且w的左孩子是红色,右孩子为黑色。
other.right.color = BLACK;
other.color = RED;
leftRotate(other);
other = parent.left;
}
// Case 4: x的兄弟w是黑色的;并且w的右孩子是红色的,左孩子任意颜色。
other.color = parent.color;
parent.color = BLACK;
other.left.color = BLACK;
rightRotate(parent);
node = root;
break;
}
}
}
if (node!=null)
node.color = BLACK;
}
//插入操作
public static void insert(int data){
Node y = null;
Node x = root;
//找到叶子节点
while(x != null) {
y = x;
if(data > x.data)
x = x.right;
else if(data < x.data)
x = x.left;
else
return;
}
//插入
Node node = new Node(data);
node.parent = y;
if(y == null)
root = node;
else
if(node.data > y.data)
y.right = node;
else
y.left = node;
node.color = RED;
//修正红黑树
insertFixUp(node);
}
private static void insertFixUp(Node node) {
Node parent, gparent;
while ((parent=node.parent)!=null && parent.color==RED) {
gparent = parent.parent;
//一、若“父节点”是“祖父节点的左孩子”
if(parent == gparent.left) {
// Case 1条件:父节点和叔叔节点是红色 则父节点、叔叔节点都为黑,祖父节点为红
Node uncle = gparent.right;
if ((uncle!=null) && uncle.color==RED) {
uncle.color = BLACK;
parent.color = BLACK;
gparent.color = RED;
node = gparent;
continue;
}
// Case 2条件:叔叔是黑色,且当前节点是右孩子,进行左转换
if (parent.right == node) {
Node tmp;
leftRotate(parent);
tmp = parent;
parent = node;
node = tmp;
}
// Case 3条件:叔叔是黑色,且当前节点是左孩子。将父节点为根的子树右旋转
parent.color = BLACK;
gparent.color = RED;
rightRotate(gparent);
} else {
//二、若“z的父节点”是“z的祖父节点的右孩子”
// Case 1条件:叔叔节点是红色
Node uncle = gparent.left;
if ((uncle!=null) && uncle.color==RED) {
uncle.color = BLACK;
parent.color = BLACK;
gparent.color = RED;
node = gparent;
continue;
}
// Case 2条件:叔叔是黑色,且当前节点是左孩子
if (parent.left == node) {
Node tmp;
rightRotate(parent);
tmp = parent;
parent = node;
node = tmp;
}
// Case 3条件:叔叔是黑色,且当前节点是右孩子。
parent.color = BLACK;
gparent.color = RED;
leftRotate(gparent);
}
}
root.color = BLACK;
}
//中序遍历
public static void midTrav(Node node){
if(node == null)
return;
midTrav(node.left);
System.out.print(node.data + " ");
midTrav(node.right);
}
//查找
public static Node searchNode(Node node, int data){
while(node != null)
if(data > node.data)
node = node.right;
else if(data < node.data)
node = node.left;
else
return node;
return node;
}
}
如果需要存储多个相同数据,Node中可以添加一个count字段,存放数量
参考:
http://www.cnblogs.com/skywang12345/p/3624343.html
http://blog.csdn.net/tcorpion/article/details/54968644