红黑树及java实现
红黑树RBT是特殊的二叉树,满足二叉查找树的特征:任意一个节点所包含的键值大于等于左子节点的键值,小于等于右子节点的键值。
红黑树的特征
- 每个节点是红色或者黑色;
- 根节点是黑色;
- 每个叶子节点是黑色的,叶子节点指的是空的叶子节点;
- 如果一个节点是红色的,则它的子节点必须是黑色的;
- 从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑色节点;
- 由特性5可以确保没有一条路径会比其他路径长出两倍。
红黑树实现
public class RBTree<T extends Comparable<T>> {
private RBTNode<T> mRoot;
private static final boolean RED = false;
private static final boolean BLACK = true;
public class RBTNode<T extends Comparable<T>> {
T key;
boolean color;
RBTNode<T> left;
RBTNode<T> right;
RBTNode<T> parent;
public RBTNode(T key, boolean color, RBTNode<T> left,
RBTNode<T> right, RBTNode<T> parent) {
this.key = key;
this.color = color;
this.left = left;
this.right = right;
this.parent = parent;
}
public T getKey(){
return key;
}
@Override
public String toString() {
return "" + key + (this.color==RED?"(R)":"B");
}
}
public RBTree() {
mRoot = null;
}
/**
* 获取父节点
*/
private RBTNode<T> parentOf(RBTNode<T> node) {
return node != null?node.parent:null;
}
/**
* 获取节点的颜色
*/
private boolean colorOf(RBTNode<T> node) {
return node != null?node.color:BLACK;
}
/**
* 判断节点是否是红色
*/
private boolean isRed(RBTNode<T> node) {
return node != null && node.color == RED;
}
/**
* 判断节点是否是黑色
*/
private boolean isRed(RBTNode<T> node) {
return !isRed(node);
}
/**
* 设置节点颜色为黑色
*/
private void setBlack(RBTNode<T> node) {
if (node != null) {
node.color = BLACK;
}
}
/**
* 设置节点颜色为红色
*/
private void setRed(RBTNode<T> node) {
if (node != null) {
node.color = RED;
}
}
/**
* 设置父节点
*/
private void setParent(RBTNode<T> node, RBTNode<T> parent) {
if (node != null) {
node.parent = parent;
}
}
/**
* 设置颜色
*/
private void setColor(RBTNode<T> node, boolean color) {
if (node != null) {
node.color = color;
}
}
/**
* 先序遍历
*/
public void preOrder() {
preOrder(mRoot);
}
private void preOrder(RBTNode<T> tree) {
if (tree != null) {
System.out.println(tree.key + " ");
preOrder(tree.left);
preOrder(tree.right);
}
}
/**
* 中序遍历
*/
public void infixOrder() {
infixOrder(mRoot);
}
private void infixOrder(RBTNode<T> tree) {
if (tree != null) {
infixOrder(tree.left);
System.out.println(tree.key + " ");
infixOrder(tree.right);
}
}
/**
* 后序遍历
*/
public void postOrder() {
postOrder(mRoot);
}
private void postOrder(RBTNode<T> tree) {
if (tree != null) {
postOrder(tree.left);
postOrder(tree.right);
System.out.println(tree.key + " ");
}
}
/**
* 递归实现:查找红黑树x中键值为key的节点
*/
public RBTNode<T> search(T key) {
return search(mRoot, key);
}
private RBTNode<T> search(RBTNode<T> x, T key) {
if (x == null) {
return null;
}
int cmp = key.compareTo(x.key);
if (cmp < 0) {
return search(x.left, key);
} else if (cmp > 0) {
return search(x.right, key);
} else {
return x;
}
}
/**
* 非递归实现:查找红黑树x中键值为key的节点
*/
public RBTNode<T> iterativeSearch(T key) {
return iterativeSearch(mRoot, key);
}
private RBTNode<T> iterativeSearch(RBTNode<T> x, T key) {
while (x != null) {
int cmp = key.compareTo(x.key);
if (cmp < 0) {
x = x.left;
} else if (cmp > 0) {
x = x.right;
} else {
return x;
}
}
return null;
}
/**
* 查找最小节点:获取tree为根节点的红黑树的最小节点
*/
public T minimum() {
RBTNode<T> node = minimum(mRoot);
if (node != null) {
return node.key;
}
return null;
}
private RBTNode<T> minimum(RBTNode<T> tree) {
if (tree == null) {
return null;
}
while(tree.left != null) {
tree = tree.left;
}
return tree;
}
/**
* 查找最大节点:获取tree为根节点的红黑树的最大节点
*/
public T maximum() {
RBTNode<T> node = maximum(mRoot);
if (node != null) {
return node.key;
}
return null;
}
private RBTNode<T> maximum(RBTNode<T> tree) {
if (tree == null) {
return null;
}
while(tree.right != null) {
tree = tree.right;
}
return tree;
}
/**
* 查找节点x的后继节点
*/
public RBTNode<T> successor(RBTNode<T> x) {
//如果x存在后继节点,后继节点是以右子节点为根的子树的最小节点
if (x.right != null) {
return minimum(x.right);
}
//如果x没有右子节点,则x有以下两种可能:
//(01)x是一个左子节点,则x的后继节点为它的父节点;
//(02)x是一个右子节点,则查找"以x的最低的父节点,并且该父节点要有左子节点",
//找到这个最低父节点就是x的后继节点
RBTNode<T> y = x.parent;
while (y != null && x == y.right) {
x = y;
y = y.parent;
}
return y;
}
/**
* 查找节点x的前驱节点(查找红黑树中数值小于该节点的最大节点)
*/
public RBTNode<T> predecessor(RBTNode<T> x) {
if (x.left != null) {
return maximum(x.left);
}
//如果x没有左子节点,则x有以下两种可能:
//(01)x是一个右子节点,则x的前驱节点为它的父节点;
//(02)x是一个左子节点,则查找"x的最低的父节点,并且该父节点要有右子节点",
//找到的这个最低的父节点就是x的前驱节点
RBTNode<T> y = x.parent;
while (y != null && x == y.left) {
x = y;
y = y.parent;
}
return y;
}
/*
* 对红黑树的节点x进行左旋转
*
* 左旋示意图(对节点x进行左旋):
* px px
* / /
* x y
* / \ --(左旋)-. / \ #
* lx y x ry
* / \ / \
* ly ry lx ly
*
*/
private void leftRotate(RBTNode<T> x) {
RBTNode<T> y = x.right; //设置x的右子节点为y
x.right = y.left; //把y的左子节点作为x的右子节点
if (y.left != null) { //如果y的左子节点非空,则把x设为"y的左子节点的父节点"
y.left.parent = x;
}
y.parent = x.parent; //把x的父节点设为y的父节点
if (x.parent == null) { //如果x的父节点是空节点,则将y设为根节点
this.mRoot = y;
} else {
if (x.parent.left == x) { //如果x是父节点的左子节点,则将y设为x的父节点的左子节点
x.parent.left = y;
} else { //如果x是父节点的右子节点,则将y设为x的父节点的右子节点
x.parent.right = y;
}
}
y.left = x; //把x设为y的左子节点
x.parent = y; //把x的父节点设为y
}
/**
* 右旋
*/
private void rightRotate(RBTNode<T> y) {
RBTNode<T> x = y.left; //设x是当前节点的左子节点
y.left = x.right;
if (x.right != null) {
x.right.parent = y;
}
x.parent = y.parent;
if(y.parent == null){
this.mRoot = x;
}else{
if(y == y.parent.right){
y.parent.right = x;
}else{
y.parent.left = x;
}
}
x.right = y;
y.parent = x;
}
/**
* 把一个节点插入到红黑树中
* 1.把红黑树当成一棵二叉查找树,把节点插入;
* 2.把插入的节点着色为红色;
* 3.通过一系列的旋转或者着色操作,把二叉树重新变成一棵红黑树。
*/
public void insert(T key) {
RBTNode<T> node = new RBTNode<T>(key, BLACK, null, null, null);
if (node != null) {
insert(node);
}
}
private void insert(RBTNode<T> node) {
int cmp;
RBTNode<T> y = null;
RBTNode<T> x = this.mRoot;
//1.把红黑树当成一棵二叉查找树,把节点插入
while (x != null) {
y = x;
cmp = node.key.compareTo(x.key);
if (cmp < 0) {
x = x.left;
} else {
x = x.right;
}
}
node.parent = y;
if (y != null) {
cmp = node.key.compareTo(y.key);
if (cmp < 0) {
y.left = node;
} else {
y.right = node;
}
} else {
this.mRoot = node;
}
//2.把插入的节点着色为红色
node.color = RED;
//3.重新修正为一棵二叉查找树
insertFixUp(node);
}
private void insertFixUp(RBTNode<T> node) {
RBTNode<T> parent, gparent;
//如果父节点存在,并且是红色的
while ((parent = parentOf(node)) != null && isRed(parent)) {
gparent = parentOf(parent);
if (parent == gparent.left) { //如果父节点是祖父节点的左子节点
RBTNode<T> uncle = gparent.right;
//case 1: 叔叔节点是红色
if (uncle != null && isRed(uncle)) {
setBlack(uncle);
setBlack(parent);
setRed(gparent);
node = gparent;
continue;
}
//case 2:叔叔节点是黑色并且当前节点是右子节点
if (parent.right == node) {
RBTNode<T> tmp;
leftRotate(parent);
tmp = parent;
parent = node;
node = tmp;
}
//case 3:叔叔节点是黑色并且当前节点是左子节点
setBlack(parent);
setRed(gparent);
rightRotate(gparent);
} else { //如果父节点是祖父节点的右子节点
//case 1:叔叔节点是红色
RBTNode<T> uncle = gparent.left;
if (uncle != null && isRed(uncle)) {
setBlack(uncle);
setBlack(parent);
setRed(gparent);
node = gparent;
continue;
}
//case 2:叔叔节点是黑色并且当前节点是左子节点
if (parent.left == node) {
RBTNode<T> tmp;
rightRotate(parent);
tmp = parent;
parent = node;
node = tmp;
}
//case 3: 叔叔节点是黑色并且当前节点是右子节点
setBlack(parent);
setRed(gparent);
leftRotate(gparent);
}
}
//把根节点设为黑色
setBlack(this.mRoot);
}
/**
* 删除节点并返回被删除的节点
*/
public void remove(T key) {
RBTNode<T> node;
if ((node = search(mRoot, key)) != null) {
remove(node);
}
}
private void remove(RBTNode<T> node) {
RBTNode<T> child, parent;
boolean color;
//被删除节点的左右子节点都不为空的情况
if (node.left != null && node.right != null) {
//被删除节点的后继节点,用来取代被删节点的位置,然后再将被删节点去掉
RBTNode<T> replace = node;
//获取后继节点
replace = replace.right;
while (replace.left != null) {
replace = replace.left;
}
//node节点是根节点则更新
if (parentOf(node) != null) {
this.mRoot = replace;
} else {
if (parentOf(node).left == node) {
parentOf(node).left = replace;
} else {
parentOf(node).right = replace;
}
}
//child是后继节点的右子节点也是需要调整的节点
child = replace.right;
parent = parentOf(replace);
color = colorOf(replace);
//被删除节点是它的后继节点的父节点
if (parent == node) {
parent = replace;
} else {
if (child != null) {
setParent(child, parent);
}
parent.left = child;
replace.right = node.right;
setParent(node.right, 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;
}
if(parent == null){
this.mRoot = child;
}else{
if(parent.left == node){
parent.left = child;
}else{
parent.right = child;
}
}
if(color == BLACK){
removeFixUp(child, parent);
}
node = null;
}
private void removeFixUp(RBTNode<T> node, RBTNode<T> parent) {
RBTNode<T> other;
while ((node==null || isBlack(node)) && (node != this.mRoot)) {
if (parent.left == node) {
other = parent.right;
if (isRed(other)) {
// Case 1: x的兄弟w是红色的
setBlack(other);
setRed(parent);
leftRotate(parent);
other = parent.right;
}
if ((other.left==null || isBlack(other.left)) &&
(other.right==null || isBlack(other.right))) {
// Case 2: x的兄弟w是黑色,且w的两个子节点也都是黑色的
setRed(other);
node = parent;
parent = parentOf(node);
} else {
if (other.right==null || isBlack(other.right)) {
// Case 3: x的兄弟w是黑色的,并且w的左子节点是红色,右子节点为黑色。
setBlack(other.left);
setRed(other);
rightRotate(other);
other = parent.right;
}
// Case 4: x的兄弟w是黑色的;并且w的右子节点是红色的,左子节点任意颜色。
setColor(other, colorOf(parent));
setBlack(parent);
setBlack(other.right);
leftRotate(parent);
node = this.mRoot;
break;
}
} else {
other = parent.left;
if (isRed(other)) {
// Case 1: x的兄弟w是红色的
setBlack(other);
setRed(parent);
rightRotate(parent);
other = parent.left;
}
if ((other.left==null || isBlack(other.left)) &&
(other.right==null || isBlack(other.right))) {
// Case 2: x的兄弟w是黑色,且w的两个子节点也都是黑色的
setRed(other);
node = parent;
parent = parentOf(node);
} else {
if (other.left==null || isBlack(other.left)) {
// Case 3: x的兄弟w是黑色的,并且w的左子节点是红色,右子节点为黑色。
setBlack(other.right);
setRed(other);
leftRotate(other);
other = parent.left;
}
// Case 4: x的兄弟w是黑色的;并且w的右子节点是红色的,左子节点任意颜色。
setColor(other, colorOf(parent));
setBlack(parent);
setBlack(other.left);
rightRotate(parent);
node = this.mRoot;
break;
}
}
}
if (node!=null)
setBlack(node);
}
/**
* 销毁红黑树
*/
public void clear() {
destroy(mRoot);
mRoot = null;
}
private void destroy(RBTNode<T> tree) {
if (tree == null) return;
if (tree.left != null) {
destroy(tree.left);
}
if(tree.right != null){
destroy(tree.right);
}
tree = null;
}
//打印红黑树
public void print() {
if (mRoot != null)
print(mRoot, mRoot.key, 0);
}
private void print(RBTNode<T> tree, T key, int direction){
//direction:0表示根节点,-1表示是左子节点,1表示是右子节点
if(tree != null){
if(direction == 0){
System.out.printf("%2d(B) is root\n", tree.key);
}else{
System.out.printf("%2d(%s) is %2d's %6s child\n",
tree.key, isRed(tree)?"R":"B",
key, direction==1?"right":"left");
}
print(tree.left, tree.key, -1);
print(tree.right, tree.key, 1);
}
}
}
红黑树测试
public class RBTreeTest {
private static final int[] a = {10, 40, 30, 60, 90, 70, 20, 50, 80};
private static final boolean mDebugInsert = false; // "插入"动作的检测开关(false,关闭;true,打开)
private static final boolean mDebugDelete = false; // "删除"动作的检测开关(false,关闭;true,打开)
public static void main(String[] args) {
int i, iLen = a.length;
RBTree<Integer> tree= new RBTree<>();
System.out.print("== 原始数据: ");
for(i=0; i<iLen; i++)
System.out.printf("%d ", a[i]);
System.out.print("\n");
for(i=0; i<iLen; i++) {
tree.insert(a[i]);
// 设置mDebugInsert=true,测试"添加函数"
if (mDebugInsert) {
System.out.printf("== 添加节点: %d\n", a[i]);
System.out.print("== 树的详细信息: \n");
tree.print();
System.out.print("\n");
}
}
System.out.print("== 前序遍历: ");
tree.preOrder();
System.out.print("\n== 中序遍历: ");
tree.infixOrder();
System.out.print("\n== 后序遍历: ");
tree.postOrder();
System.out.print("\n");
System.out.printf("== 最小值: %s\n", tree.minimum());
System.out.printf("== 最大值: %s\n", tree.maximum());
System.out.print("== 树的详细信息: \n");
tree.print();
System.out.print("\n");
// 设置mDebugDelete=true,测试"删除函数"
if (mDebugDelete) {
for(i=0; i<iLen; i++)
{
tree.remove(a[i]);
System.out.printf("== 删除节点: %d\n", a[i]);
System.out.print("== 树的详细信息: \n");
tree.print();
System.out.print("\n");
}
}
// 销毁二叉树
tree.clear();
}
}
== 原始数据: 10 40 30 60 90 70 20 50 80
== 前序遍历: 30 10 20 60 40 50 80 70 90
== 中序遍历: 10 20 30 40 50 60 70 80 90
== 后序遍历: 20 10 50 40 70 90 80 60 30
== 最小值: 10
== 最大值: 90
== 树的详细信息:
30(B) is root
10(B) is 30’s left child
20® is 10’s right child
60® is 30’s right child
40(B) is 60’s left child
50® is 40’s right child
80(B) is 60’s right child
70® is 80’s left child
90® is 80’s right child