一、什么是红黑树
红黑树(Red Black Tree) 是一种自平衡二叉查找树,是在计算机科学中用到的一种数据结构,典型的用途是实现关联数组。
它是在1972年由Rudolf Bayer发明的,当时被称为平衡二叉B树(symmetric binary B-trees)。后来,在1978年被 Leo J. Guibas 和 Robert Sedgewick 修改为如今的“红黑树”(百度百科)
红黑树是一棵二叉搜索树,它在每个结点上增加了一个存储位来表示结点的颜色,可以是RED或BLACK。
一棵红黑树是满足下面红黑性质的二叉搜索树:
1、每一个结点或是红结点或是黑结点
2、根节点是黑色的
3、每个叶节点(NIL)是黑色的
4、如果一个结点是红色的,则它的两个子节点都是黑色的
5、对每个结点,从该节点到其所以后代叶节点的简单路径上,均包含相同数目的黑色结点
二、旋转操作
由于树的插入和删除操作会破坏红黑树的性质,为了维护这些性质,必须要改变树中某些结点的颜色以及指针结构,指针结构的修改是通过旋转来完成的,这是一种能保持二叉树搜索性质的搜索树局部操作。
旋转有两种。左旋和右旋
/** * x左旋转 * @param root * @param x */ public void Left_Rotate(Node root,Node x){ Node y = x.right; x.right = y.left;//把y的左子树赋给x的右子树 if(y.left!=null){ y.left.p = x; } y.p = x.p; if(x.p==null){ root = y; }else if(x==x.p.left){ x.p.left = y; }else{ x.p.right = y; } y.left = x; //让x成为y的左子树 x.p = y; } /** * x右旋转 * @param root * @param x */ public void Right_Rotate(Node root,Node x){ Node y = x.left; x.left = y.right; if(y.right!=null){ y.right.p = x; } y.p = x.p; if(x.p==null){ root = y; }else if(x == x.p.left){ x.p.left = y; }else{ x.p.right = y; } y.right = x; x.p = y; }
三、插入操作
基本上和二叉搜索树的插入一样,只是将插入的z的颜色着红
public void RB_Insert(Node root,Node z){
Node y = null;
Node x = root;
while(x!=null){
y = x;
if(z.k<x.k){
x = x.left;
}else{
x = x.right;
}
}
z.p = y;
if(y==null){
root = z;
}else if(z.k<y.k){
y.left = z;
}else{
y.right = z;
}
z.right = null;
z.left = null;
z.color = "RED";
RB_Insert_Fixup(root,z);//调整
}
对数据插入后会破坏红黑树的性质,所以需要进行调整。
分为下面三种情况
1、z的叔父结点y是红色的
由于z的父节点z->p和叔节点都是红色,所以z的祖父节点z->p->p的颜色一定是黑色,这是因为插入之前是一颗“完好”的红黑树。
对于这种情况,处理办法是:将z的父节点和叔节点都染黑,而将z的祖父节点染红,这样做了之后,我们仔细思考一下,发现其实这样对当前树的走父节点或走叔节点的路 径的黑节点数没有影响。然后这时我们再将z点指向z的祖父节点位置,然后继续进入循环
2、z的叔父结点y是黑色的,且z是一个右孩子
这里的做法就是将二情况转换成三情况,当然就要用到旋转,但是我们又不希望z的位置发现变化,所以这里先让z=z->p,然后再以z为支点进行左旋,因为左旋会让z下降一级,所以实际上z还是指向的原来那一层的节点,z->p->p的位置还是没有变。
3、z的叔父结点y是黑色的,且z是一个左孩子
这时实际上是z和z->p都是红色,z->p->p和z.->p->right都是黑色,我们想做的就是让z和z->p之间多个黑节点,这样就能满足性质4,但是同时我们又希望保持性质5。于是我们这样处理:
z->p染黑,z->p->p染红,然后以z->p->p为支点右旋,这样就搞定了
public void RB_Insert_Fixup(Node root,Node z){
while(z.p.color=="RED"){
if(z.p==z.p.p.left){
Node y = z.p.p.right;
if(y.color=="RED"){//第一种情况,z的叔父结点为红色
z.p.color="BLACK";
y.color = "BLACK";
z.p.p.color ="RED";
z = z.p.p;
}else if(z==z.p.right){//第二种情况 z的叔父结点为黑色且z是一个右孩子
z = z.p;
Left_Rotate(root, z);
}else{
//第三种情况 z的叔父结点为黑色 且z是一个左孩子
z.p.color = "BLACK";
z.p.p.color = "RED";
Right_Rotate(root, z.p.p);
}
}else{
//same as then clause with "right" and "left" exchanged
Node y = z.p.p.left;
if(y.color=="RED"){//第一种情况,z的叔父结点为红色
z.p.color="BLACK";
y.color = "BLACK";
z.p.p.color ="RED";
z = z.p.p;
}else if(z==z.p.left){//第二种情况 z的叔父结点为黑色且z是一个左孩子
z = z.p;
Right_Rotate(root, z);
}else{
//第三种情况 z的叔父结点为黑色 且z是一个右孩子
z.p.color = "BLACK";
z.p.p.color = "RED";
Left_Rotate(root, z.p.p);
}
}
}
root.color = "BLACK";
}
参考《算法导论》
http://blog.csdn.net/cyp331203/article/details/42677833
http://www.cnblogs.com/dongkuo/p/4922058.html