红黑树
红黑树介绍
红黑树是一种特殊的二叉查找树,为什么说红黑树特殊呢?因为红黑树既满足二叉查找树的特点,又满足以下5条性质。
- 红黑树的根节点是黑色的
- 红黑树的节点非黑即红,不能既是黑色又是白色
- 红色节点的只能有两个黑色的子节点
- 叶子节点值得是NiL,叶子节点是黑色的
- 任何一个节点到它所有的叶子节点的黑节点个数相同
特性5确保了 从根节点到叶子节点的最长路径不会超过最短路径的两倍。
原理部分具体参考该大神的博客
有点错误,但总体上还是正确的。
左旋代码:
private void leftRotate(RBTNode<T> x) {
RBTNode<T> y = x.right; //x.right可不可能为空,先假设不可能为空
x.right = y.left;
if(y.left != null)
y.left.parent = x;
y.parent = x.parent;
if(x.parent == null)
this.mRoot = y;
else {
if(x.parent.left == x)
x.parent.left = y;
else
x.parent.right = y;
}
y.left = x;
x.parent = y;
}
右旋代码:
private void rightRotate(RBTNode<T> x) {
RBTNode<T> y = x.left;
x.left = y.right;
if(y.right!= null)
y.right.parent = x;
y.parent = x.parent;
if(x.parent == null)
this.mRoot = y;
else {
if(x.parent.left == x)
x.parent.left = y;
else
x.parent.right = y;
}
y.right = x;
x.parent = y;
}
插入代码:
public void insert(RBTNode<T> node) {
int cmp;
RBTNode x = this.mRoot;
RBTNode y = null;
while(x!=null) {
y = x;
cmp = x.key.compareTo(node.key);
if(cmp > 0)
x = x.left;
else
x = x.right;
}
if(y != null) {
node.parent = y;
cmp = y.key.compareTo(node.key);
if(cmp > 0)
y.left = node;
else
y.right = node;
}else
this.mRoot = node;
/*
* if(node.parent!=null) System.out.println("#" + node.parent.key + " " +
* node.key); else System.out.println("#" + node.key);
*/
node.color = RED;
insertFixUp(node);
}
插入修正:
public void insertFixUp(RBTNode<T> node) {
RBTNode parent,gparent,uncle;
//父节点不为空,并且是红色
while((parent = parentOf(node))!=null && isRed(parent)) {
//猜测无论如何不可能根节点为红还能访问他的parent
gparent = parentOf(parent);
if(parent == gparent.left) {
//情况1
uncle = gparent.right;
if(uncle !=null && isRed(uncle)) {
setBlack(parent);
setBlack(uncle);
setRed(gparent);
node = gparent;
continue;
}
//情况2 uncle为空 或者 黑 其实空也是黑节点
if(node == parent.right) {
leftRotate(parent);
RBTNode<T> temp;
temp = parent;
parent = node;
node = temp;
}
setBlack(parent);
setRed(gparent);
rightRotate(gparent);
}else {
uncle = gparent.left;
//情况1 uncle为红色
if(uncle!=null && isRed(uncle)) {
setBlack(parent);
setBlack(uncle);
setRed(gparent);
node = gparent;
continue;
}
//情况2 uncle为空 或者 黑 其实空也是黑节点
if(node == parent.left) {
rightRotate(parent);
RBTNode<T> temp;
temp = parent;
parent = node;
node = temp;
}
setBlack(parent);
setRed(gparent);
leftRotate(gparent);
}
}
//最终要把根节点设置成黑色
setBlack(mRoot);
}
删除节点代码:
public void remove(RBTNode<T> node) {
RBTNode parent,child;
boolean color ;
//如果被删除节点的左右子树都不为空,那么就得找到其后继节点
if((node.left!=null) && node.right!=null) {
RBTNode<T> replace;
//找他的后继节点
replace = node.right;
while(replace.left!=null)
replace = replace.left;
parent = parentOf(replace);
child = replace.right;
//如果删除的不是根节点
if(node.parent != null) {
if(node.parent.left == node)
node.parent.left = replace;
else
node.parent.right = replace;
}else
this.mRoot = replace;
if(parent == node)
parent = replace;
else {
parent.left = child;
if(child!=null)
child.parent = parent;
replace.right = node.right;
node.right.parent = replace;
}
replace.parent = node.parent;
replace.left = node.left;
node.left.parent = replace;
color = replace.color;
if(color == BLACK) {
//调整删除
removeFixUp(child,parent);
}
node = null;
return ;
}
//只有左孩子 或者 右孩子 或者 没有
if(node.left!=null)
child = node.left;
else
child = node.right;
parent = node.parent;
if(child!=null)
child.parent = parent;
if(parent!=null)
if(parent.left == node)
parent.left = child;
else
parent.right = child;
else
this.mRoot = child;
color = node.color;
node = null;
if(color == BLACK)
removeFixUp(child,parent); //删除根几点parent可能为空
//找到后继节点
}
删除修正:
public 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)) {
setBlack(other);
setRed(parent);
leftRotate(parent);
other = parent.right;
}
//如果x的兄弟节点是黑色并且他的左孩子右孩子节点也都是黑色
if((other.left == null || isBlack(other.left)) && (other.right == null || isBlack(other.right))) {
setRed(other);
node = parent;
parent = parent.parent;
}else {
//右孩子节点是黑色,左孩子节点是红色
if(other.right == null || isBlack(other.right)) {
setBlack(other.left);
setRed(other);
rightRotate(other);
node = parent.right;
}
//兄弟的右孩子节点是红色节点
other.color = parent.color;
setBlack(parent);
setBlack(other.right);
leftRotate(parent);
node = this.mRoot;
break;
}
}else {
other = parent.left;
if(isRed(other)) {
setBlack(other);
setRed(parent);
rightRotate(parent);
other = parent.left;
}
if((other.left == null || isBlack(other.left)) && (other.right == null || isBlack(other.right))) {
setRed(other);
node = parent;
parent = parent.parent;
}else {
//左孩子节点是黑色节点,右孩子孩子节点是红色节点
if(other.left == null || isBlack(other.left)) {
setBlack(other.right);
setRed(other);
leftRotate(other);
node = parent.left;
}
//兄弟的左孩子节点是红色节点
other.color = parent.color;
setBlack(parent);
setBlack(other.left);
rightRotate(parent);
node = this.mRoot;
break;
}
}
}
if(node!=null)
setBlack(node);
}
全部代码:
public class RBTree <T extends Comparable<T>>{ //T这个类型必须实现了Comparable的compareTo方法
private RBTNode<T> mRoot;
private static final boolean RED = false;
private static final boolean BLACK = true;
public class RBTNode<T extends Comparable<T> >{
boolean color ;
T key;
RBTNode<T> left;
RBTNode<T> right;
RBTNode<T> parent;
public RBTNode(T key,boolean color,RBTNode<T> parent,RBTNode<T> left,RBTNode<T> right) {
this.key = key;
this.color = color;
this.parent = parent;
this.left = left;
this.right = right;
}
}
private void leftRotate(RBTNode<T> x) {
RBTNode<T> y = x.right; //x.right可不可能为空,先假设不可能为空
x.right = y.left;
if(y.left != null)
y.left.parent = x;
y.parent = x.parent;
if(x.parent == null)
this.mRoot = y;
else {
if(x.parent.left == x)
x.parent.left = y;
else
x.parent.right = y;
}
y.left = x;
x.parent = y;
}
private void rightRotate(RBTNode<T> x) {
RBTNode<T> y = x.left;
x.left = y.right;
if(y.right!= null)
y.right.parent = x;
y.parent = x.parent;
if(x.parent == null)
this.mRoot = y;
else {
if(x.parent.left == x)
x.parent.left = y;
else
x.parent.right = y;
}
y.right = x;
x.parent = y;
}
public void insert(RBTNode<T> node) {
int cmp;
RBTNode x = this.mRoot;
RBTNode y = null;
while(x!=null) {
y = x;
cmp = x.key.compareTo(node.key);
if(cmp > 0)
x = x.left;
else
x = x.right;
}
if(y != null) {
node.parent = y;
cmp = y.key.compareTo(node.key);
if(cmp > 0)
y.left = node;
else
y.right = node;
}else
this.mRoot = node;
/*
* if(node.parent!=null) System.out.println("#" + node.parent.key + " " +
* node.key); else System.out.println("#" + node.key);
*/
node.color = RED;
insertFixUp(node);
}
public void insert(T key) {
RBTNode<T> node = new RBTNode<T>(key,BLACK,null,null,null);
if(node!=null) {
insert(node);
}
}
public RBTNode<T> parentOf(RBTNode<T> node){
return node.parent;
}
public boolean isRed(RBTNode<T> node) {
if(!node.color)
return true;
else
return false;
}
public boolean isBlack(RBTNode<T> node) {
if(node.color)
return true;
else
return false;
}
public void setBlack(RBTNode<T> node) {
node.color = BLACK;
}
public void setRed(RBTNode<T> node) {
node.color = RED;
}
public void insertFixUp(RBTNode<T> node) {
RBTNode parent,gparent,uncle;
//父节点不为空,并且是红色
while((parent = parentOf(node))!=null && isRed(parent)) {
//猜测无论如何不可能根节点为红还能访问他的parent
gparent = parentOf(parent);
if(parent == gparent.left) {
//情况1
uncle = gparent.right;
if(uncle !=null && isRed(uncle)) {
setBlack(parent);
setBlack(uncle);
setRed(gparent);
node = gparent;
continue;
}
//情况2 uncle为空 或者 黑 其实空也是黑节点
if(node == parent.right) {
leftRotate(parent);
RBTNode<T> temp;
temp = parent;
parent = node;
node = temp;
}
setBlack(parent);
setRed(gparent);
rightRotate(gparent);
}else {
uncle = gparent.left;
//情况1 uncle为红色
if(uncle!=null && isRed(uncle)) {
setBlack(parent);
setBlack(uncle);
setRed(gparent);
node = gparent;
continue;
}
//情况2 uncle为空 或者 黑 其实空也是黑节点
if(node == parent.left) {
rightRotate(parent);
RBTNode<T> temp;
temp = parent;
parent = node;
node = temp;
}
setBlack(parent);
setRed(gparent);
leftRotate(gparent);
}
}
//最终要把根节点设置成黑色
setBlack(mRoot);
}
private void preOrder(RBTNode<T> tree) {
if(tree == null)
return;
System.out.print(tree.key + ":");
System.out.println(tree.color == true?"black":"red");
preOrder(tree.left);
preOrder(tree.right);
}
public void preOrder() {
preOrder(this.mRoot);
}
private void inOrder(RBTNode<T> tree) {
if(tree == null)
return;
inOrder(tree.left);
System.out.print(tree.key + " ");
inOrder(tree.right);
}
public void inOrder() {
inOrder(this.mRoot);
}
private void postOrder(RBTNode<T> tree) {
if(tree == null)
return;
postOrder(tree.left);
postOrder(tree.right);
System.out.print(tree.key + " ");
}
public void postOrder() {
postOrder(this.mRoot);
}
public void remove(RBTNode<T> node) {
RBTNode parent,child;
boolean color ;
//如果被删除节点的左右子树都不为空,那么就得找到其后继节点
if((node.left!=null) && node.right!=null) {
RBTNode<T> replace;
//找他的后继节点
replace = node.right;
while(replace.left!=null)
replace = replace.left;
parent = parentOf(replace);
child = replace.right;
//如果删除的不是根节点
if(node.parent != null) {
if(node.parent.left == node)
node.parent.left = replace;
else
node.parent.right = replace;
}else
this.mRoot = replace;
if(parent == node)
parent = replace;
else {
parent.left = child;
if(child!=null)
child.parent = parent;
replace.right = node.right;
node.right.parent = replace;
}
replace.parent = node.parent;
replace.left = node.left;
node.left.parent = replace;
color = replace.color;
if(color == BLACK) {
//调整删除
removeFixUp(child,parent);
}
node = null;
return ;
}
//只有左孩子 或者 右孩子 或者 没有
if(node.left!=null)
child = node.left;
else
child = node.right;
parent = node.parent;
if(child!=null)
child.parent = parent;
if(parent!=null)
if(parent.left == node)
parent.left = child;
else
parent.right = child;
else
this.mRoot = child;
color = node.color;
node = null;
if(color == BLACK)
removeFixUp(child,parent); //删除根几点parent可能为空
//找到后继节点
}
//查找值
public RBTNode<T> search(RBTNode<T> node,T key) {
if(node == null)
return node;
int cmp;
cmp = node.key.compareTo(key);
if(cmp > 0)
return search(node.left, key);
else if(cmp<0)
return search(node.right, key);
else
return node;
}
public void remove(T key) {
RBTNode<T> node;
if((node = search(mRoot,key))!=null) {
remove(node);
}
}
public 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)) {
setBlack(other);
setRed(parent);
leftRotate(parent);
other = parent.right;
}
//如果x的兄弟节点是黑色并且他的左孩子右孩子节点也都是黑色
if((other.left == null || isBlack(other.left)) && (other.right == null || isBlack(other.right))) {
setRed(other);
node = parent;
parent = parent.parent;
}else {
//右孩子节点是黑色,左孩子节点是红色
if(other.right == null || isBlack(other.right)) {
setBlack(other.left);
setRed(other);
rightRotate(other);
node = parent.right;
}
//兄弟的右孩子节点是红色节点
other.color = parent.color;
setBlack(parent);
setBlack(other.right);
leftRotate(parent);
node = this.mRoot;
break;
}
}else {
other = parent.left;
if(isRed(other)) {
setBlack(other);
setRed(parent);
rightRotate(parent);
other = parent.left;
}
if((other.left == null || isBlack(other.left)) && (other.right == null || isBlack(other.right))) {
setRed(other);
node = parent;
parent = parent.parent;
}else {
//左孩子节点是黑色节点,右孩子孩子节点是红色节点
if(other.left == null || isBlack(other.left)) {
setBlack(other.right);
setRed(other);
leftRotate(other);
node = parent.left;
}
//兄弟的左孩子节点是红色节点
other.color = parent.color;
setBlack(parent);
setBlack(other.left);
rightRotate(parent);
node = this.mRoot;
break;
}
}
}
if(node!=null)
setBlack(node);
}
}
测试代码:
public class BRTreeTest {
private static final int a[] = {10, 40, 30, 60, 90, 70, 20, 50, 80};
public static void main(String[] args) {
int len = a.length;
RBTree<Integer> tree = new RBTree<Integer>();
System.out.println("原数据");
for(int i=0;i<len;i++) {
System.out.print(a[i] + " ");
if(i == len) System.out.print("\n");
}
for(int i=0;i<len;i++) {
tree.insert(a[i]);
}
System.out.println();
System.out.println("前序遍历================================");
tree.preOrder();
System.out.println();
System.out.println("中序遍历================================");
tree.inOrder();
System.out.println();
System.out.println("后序遍历================================");
tree.postOrder();
tree.remove(30);
System.out.println();
System.out.println("删除第一个节点的前序遍历================================");
tree.preOrder();
System.out.println();
System.out.println("中序遍历================================");
tree.inOrder();
}
}