E81086713E446D36F62B2AA2A3502B5EB155

Java杂家

杂七杂八。。。一家之言

BlogJava 首页 新随笔 联系 聚合 管理
  141 Posts :: 1 Stories :: 174 Comments :: 0 Trackbacks
红黑树可能是要考虑情况最多的BST树了,它有自己的规则(见代码的注释),通过这些规则可以保证花费较小的代价来达到相对平衡。
注意,红黑树仍然不是平衡树,但是统计性能要好于AVL树。
要保持红黑树的规则,主要通过两类操作,一类是换色,一类还是旋转。
红黑树插入主要要解决红-红冲突,而删除主要则解决“双黑”

同样,红黑树的删除节点实现是最复杂的,不过,复杂也就在于考虑的情况多,掌握了这几种情况实现还是不困难。
其实,红黑树其实是一颗扩充的二叉树,所以也是满二叉树,其空节点可以看做是扩充的叶节点。但是红黑树的扩充叶节点是有特殊意义的。


下面是代码:

package algorithms.tree;

/**
 * R-B Tree has following four rules:
 * 1)every node is either red or black
 * 2)root and empty node (external leaf node) are always black.
 * 3)the red node's parent node must be black
 * 4)every simple path start from node X to its descendant contains same number of black node
 * 
 * 
 * 
@author yovn
 *
 
*/
public class RBTree<extends Comparable<E>> extends DefaultBSTree<E> implements BSTree<E> {

    
    
    
public static class RBPrinter<extends Comparable<E>> implements DefaultBSTree.NodeVisitor<E>
    {

        @Override
        
public void visit(E ele) {
            
            
        }

        @Override
        
public void visitNode(algorithms.tree.DefaultBSTree.BSTNode<E> node) {
            RBNode
<E> n=(RBNode<E>)node;
            
if(!n.isNull())
            System.out.print(n.key
+"("+(n.color==RBNode.RED?"RED":"BLACK")+"),");
            
        }
        
    }
    
static class RBNode<extends Comparable<E>> extends BSTNode<E>
    {



        
static final boolean RED=false;
        
static final boolean BLACK=true;
        
        
        
        RBNode
<E> parent;
        
boolean color;//red or black
        
        
        RBNode(RBNode
<E> p,E key,boolean color) {
            
super(key);
            
this.color=color;
            
this.parent=p;
            
        }
        
        
        
        
final boolean isNull(){return key==null;}
        
    }
    
    
        
    @Override
    
public final boolean delete(E ele) {
        RBNode
<E> cur;
        
        
int cmp;
        
if(root==null)return false;
        cur
=(RBNode<E>)root;
        
while(!cur.isNull()&&(cmp=ele.compareTo(cur.key))!=0)
        {
            
if(cmp<0)cur=(RBNode<E>)cur.left;
            
else cur=(RBNode<E>)cur.right;
                
        }
        
if(cur.isNull())
        {
            
//can't find specified key
            return false;
        }
        
if(!((RBNode<E>)cur.left).isNull()&&!((RBNode<E>)cur.right).isNull())
        {
            RBNode
<E> prev=(RBNode<E>)cur.left;
        
            
while(!((RBNode<E>)prev.right).isNull())
            {
                
                prev
=(RBNode<E>)prev.right;
            }
            cur.key
=prev.key;
            cur
=prev;
        
        }
        
if(!((RBNode<E>)cur.left).isNull())
        {
            
if (cur == root) {
                root 
= cur.left;
                ((RBNode
<E>)root).color=RBNode.BLACK;
                
return true;
            }
            
            
if(cur.parent.left==cur)
            {
                cur.parent.left
=cur.left;
                ((RBNode
<E>)cur.left).parent=cur.parent;
            }
            
else
            {
                cur.parent.right
=cur.left;
                ((RBNode
<E>)cur.left).parent=cur.parent;
            }
            
if(cur.color==RBNode.BLACK)
            {
                ((RBNode
<E>)cur.left).color=RBNode.BLACK;
            }
        }
        
else if(!((RBNode<E>)cur.right).isNull())
        {
            
if (cur == root) {
                root 
= cur.right;
                ((RBNode
<E>)root).color=RBNode.BLACK;
                
return true;
            }
            
            
if(cur.parent.left==cur)
            {
                cur.parent.left
=cur.right;
                ((RBNode
<E>)cur.right).parent=cur.parent;
            }
            
else
            {
                cur.parent.right
=cur.right;
                ((RBNode
<E>)cur.right).parent=cur.parent;
            }
            
if(cur.color==RBNode.BLACK)
            {
                ((RBNode
<E>)cur.right).color=RBNode.BLACK;
            }
        }
        
else
        {
            
if(cur==root)
            {
                root
=null;
                
return true;
            }
            RBNode
<E> todo;
            
if(cur.parent.left==cur)
            {
                todo
=newNullNode(cur.parent);
                cur.parent.left
=todo;
            }
            
            
else
            {
                todo
=newNullNode(cur.parent);
                cur.parent.right
=todo;
            }
            
if(cur.color==RBNode.BLACK)
            {
                
//now todo is a double black node, we will eliminate the double black
                fixup_double_black(todo);
            }
            
        }
        
        
return true;
    }

    @Override
    
public E findMax() {
        
if(isEmpty())return null;
        BSTNode
<E> node=root;
        
while(!((RBNode<E>)node.right).isNull())
        {
            node
=node.right;
        }
        
return node.key;
    }


    @Override
    
public E findMin() {
        
if(isEmpty())return null;
        BSTNode
<E> node=root;
        
while(!((RBNode<E>)node.left).isNull())
        {
            node
=node.left;
        }
        
return node.key;
    }

    
private final RBNode<E> newNullNode(RBNode<E> p)
    {
        
return new RBNode<E>(p,null,RBNode.BLACK);
    }
    
    
private final RBNode<E> newNormalNode(RBNode<E> p,E key, boolean color)
    {
        RBNode
<E> node= new RBNode<E>(p,key,color);
        node.left
=newNullNode(node);
        node.right
=newNullNode(node);
        
return node;
    }

    
private final void fixup_double_black(RBNode<E> cur) {
        
        RBNode
<E> sibling;
        RBNode
<E> p;
    
        
while(cur!=root)//until its parent,parent maybe double black 
        {
            p
=cur.parent;
            
if(p.left==cur)
            {
                sibling
=(RBNode<E>)p.right;
                
if(sibling.color==RBNode.RED)
                {
                    rotate_from_right(p);
                    p.color
=RBNode.RED;
                    sibling.color
=RBNode.BLACK;//actually, p.parent==sibling, remember we have done one rotation
                    
//this case  transformed to another case handled in other place
                }
                
else 
                {
                    
if(((RBNode<E>)sibling.right).color==RBNode.RED)
                    {
                        rotate_from_right(p);
                        sibling.color
=p.color;//also, p.parent==sibling, some textbook say here sibling's color can be red while not violate the 3th rule, i don't think so.
                        p.color=RBNode.BLACK;
                        ((RBNode
<E>)sibling.right).color=RBNode.BLACK;
                        
//ok done!
                        return;
                        
                    }
                    
else if(((RBNode<E>)sibling.left).color==RBNode.RED)
                    {
                        rotate_from_left(sibling);
                        sibling.color
=RBNode.RED;
                        sibling.parent.color
=RBNode.BLACK;//its parent was previously be its left child, remember we have done a left rotation from sibling
                        
                        
// now transformed to previous case, double black 's sibling(black) have right child colored red
                        
                    }
                    
else //  sibling's two children are both black
                    {
                        
//re-coloring the sibling and parent
                        sibling.color=RBNode.RED;
                        
if(p.color==RBNode.BLACK)
                        {
                            cur
=p;
                            
//now the cur node was not double black node ,but p was a double black
                        }
                        
else
                        {
                            p.color
=RBNode.BLACK;//eliminated the double black node 
                            return;
                        }
                    }
                }
            }
            
else
            {
                sibling
=(RBNode<E>)p.left;
                
if(sibling.color==RBNode.RED)
                {
                    rotate_from_left(p);
                    p.color
=RBNode.RED;
                    sibling.color
=RBNode.BLACK;//actually, p.parent==sibling, remember we have done one rotation
                    
//this case  transformed to another case handled in other place
                }
                
else 
                {
                    
if(((RBNode<E>)sibling.left).color==RBNode.RED)
                    {
                        rotate_from_left(p);
                        sibling.color
=p.color;//also, p.parent==sibling, some textbook say here sibling's color can be red while not violate the 3th rule, i don't think so.
                        p.color=RBNode.BLACK;
                        ((RBNode
<E>)sibling.left).color=RBNode.BLACK;
                        
//ok done!
                        return;
                        
                    }
                    
else if(((RBNode<E>)sibling.right).color==RBNode.RED)
                    {
                        rotate_from_right(sibling);
                        sibling.color
=RBNode.RED;
                        sibling.parent.color
=RBNode.BLACK;//its parent was previously be its right child, remember we have done a left rotation from sibling
                    
                        
// now transformed to previous case, double black 's sibling(black) have right child colored red
                        
                    }
                    
else //  sibling's two children are both black
                    {
                        
//re-coloring the sibling and parent
                        sibling.color=RBNode.RED;
                        
if(p.color==RBNode.BLACK)
                        {
                            cur
=p;
                            
//now the cur node was not double black node ,but p was a double black
                        }
                        
else
                        {
                            p.color
=RBNode.BLACK;//eliminated the double black node 
                            return;
                        }
                    }
                }
            }
        }
        
    }

    



    @Override
    
public final void insert(E ele) {
        
if(root==null)
        {
            root
=newNormalNode(null,ele,RBNode.BLACK);//now root's black-height(bh) is 1
            return;
        }
        RBNode
<E> ret=_insert((RBNode<E>)root,ele);//first insert it
        _insert_fixup(ret);//fix-up the R-B tree from node cur;
    }
    
    
    
private final void _insert_fixup(RBNode<E> cur) {
        
        RBNode
<E> p,g;
    
        
//we should fix until it is black colored
        while(cur!=root&&cur.color==RBNode.RED)
        {
            p
=cur.parent;
            
if(p.color==RBNode.BLACK)
            {
                
//that's fine, the insertion will not change any black height, and will not violate any rule.
                return;
            }
            g
=p.parent;//we can assume the p is not null now.
            
            
if(p==g.left)
            {
                RBNode
<E> uncle=(RBNode<E> )g.right;
                
if(uncle.color==RBNode.RED)
                {
                    
//re-coloring
                    g.color=RBNode.RED;
                    uncle.color
=p.color=RBNode.BLACK;
                    
                    
//now the g maybe conflict with its parent;
                    cur=g;
                }
                
else
                {
                    
if(cur==p.right)
                    {
                        
//this case we should do left rotation, and then it will transform to next case
                        cur=rotate_from_right(p);
                        cur
=(RBNode<E>)cur.left;
                        
//transformed to next case    
                    }
                    
                    cur
=rotate_from_left(g);
                    cur.color
=RBNode.BLACK;
                    ((RBNode
<E>)cur.left).color=((RBNode<E>)cur.right).color=RBNode.RED;
                                    
                
                }
                
            }
            
else
            {
                RBNode
<E> uncle=(RBNode<E> )g.left;
                
if(uncle.color==RBNode.RED)
                {
                    
//re-coloring
                    g.color=RBNode.RED;
                    uncle.color
=p.color=RBNode.BLACK;
                    
                    
//now the g maybe conflict with its parent;
                    cur=g;
                }
                
else
                {
                    
if(cur==p.left)
                    {
                        
//this case we should do right rotation, and then it will transform to next case
                        cur=rotate_from_left(p);
                        cur
=(RBNode<E>)cur.right;
                        
//transformed to next case    
                    }
                    
                    cur
=rotate_from_right(g);
                    cur.color
=RBNode.BLACK;
                    ((RBNode
<E>)cur.left).color=((RBNode<E>)cur.right).color=RBNode.RED;
                                    
                
                }
            }
                
        }
        ((RBNode
<E>)root).color=RBNode.BLACK;
        
        
    }




    
private final RBNode<E> rotate_from_right(RBNode<E> p) {
        
        RBNode
<E> g=p.parent;
        RBNode
<E> cur=(RBNode<E>)p.right;
        
        p.right
=cur.left;
        
if(cur.left!=null)((RBNode<E>)cur.left).parent=p;
        
        cur.left
=p;
        p.parent
=cur;
        
        
        
if(g!=null)
        {
            
if(g.left==p)g.left=cur;
            
else g.right=cur;
        }
        
else root=cur;
        
        cur.parent
=g;
        
return cur;
        
    
    }




    
private final RBNode<E> rotate_from_left(RBNode<E> p) {
        RBNode
<E> g=p.parent;
        RBNode
<E> cur=(RBNode<E>)p.left;
        
        p.left
=cur.right;
        
if(cur.right!=null)((RBNode<E>)cur.right).parent=p;
        
        cur.right
=p;
        p.parent
=cur;
        
        
        
if(g!=null)
        {
            
if(g.left==p)g.left=cur;
            
else g.right=cur;
        }
        
else root=cur;
        
        cur.parent
=g;
        
return cur;
    }




    
private final RBNode<E> _insert(RBNode<E> cur,E ele)
    {
        
        RBNode
<E> parent=null;
        
int cmp;
        
boolean left=false;
        
while(!cur.isNull()&&(cmp=ele.compareTo(cur.key))!=0)
        {
            parent
=cur;
            
if(cmp<0)
            {
                cur
=(RBNode<E>)cur.left;
                left
=true;
                
            }
            
else {cur=(RBNode<E>)cur.right;left=false;}
            
        }
        
if(!cur.isNull())throw new IllegalArgumentException("can't insert duplicate key!");
        cur
=newNormalNode(parent,ele,RBNode.RED);
        
if(left)parent.left=cur;
        
else parent.right=cur;
        
return cur;
    }




    
/**
     * 
     
*/
    
public RBTree() {
            root
=null;
    }

}





posted on 2007-12-20 18:25 DoubleH 阅读(8489) 评论(20)  编辑  收藏

Feedback

# re: 红黑树的Java实现 2007-12-23 22:43 bwl
似乎是老外写的。。。。。。。。  回复  更多评论
  

# re: 红黑树的Java实现 2007-12-24 12:26 Javacap
@bwl
不好意思,我通常写代码都喜欢英文注释,很少写中文注释,要么就干脆不注释,老感觉写代码加上中文注释挺别扭的,代码哪怕一个字也没有参看别人的。  回复  更多评论
  

# re: 红黑树的Java实现 2007-12-24 14:47 过路
Java功底不错。
  回复  更多评论
  

# re: 红黑树的Java实现[未登录] 2008-02-14 18:20 wangj
可能你使用的Java的IDE对中文支持不好,良好的代码是要尽量给别人看的,只要有基础的人看不懂,特别加了注释还不如不加的话,那最好不加。
其实很多JSP和J2ME程序都要使用中文的,因为毕竟面对的是中文界面用户,从理论上来说数据结构是不需要中文的,但是数据结构一般都是用C或者Delphi编的,然后通过JNI调用的,因此用Java就是用对象,你可惜做的并不好  回复  更多评论
  

# re: 红黑树的Java实现[未登录] 2008-02-14 18:24 wangj
@Javacap
你的程序还不是老外写的,如果向老外看齐的话,请先把软件书写规范点。问题太多了,直说2点吧,第一等号两边都要空格,第二,多条语句必须写多行
  回复  更多评论
  

# re: 红黑树的Java实现[未登录] 2009-01-14 11:41 wangj
@wangj
2b真多  回复  更多评论
  

# re: 红黑树的Java实现[未登录] 2009-01-14 16:59 wangj
wangj = 2b
  回复  更多评论
  

# re: 红黑树的Java实现 2009-07-28 15:35 satitan
如果提不出实质性的意见,请像我一样称赞一下博主的OPEN精神:非常好,已阅  回复  更多评论
  

# re: 红黑树的Java实现 2009-08-19 22:03 lixmin
我喜欢, 已阅  回复  更多评论
  

# re: 红黑树的Java实现[未登录] 2009-12-10 22:53 Daniel
@wangj

请那些不懂算法别在这里乱评论,正如有位仁兄所说“2B真多”
楼主我很欣赏  回复  更多评论
  

# re: 红黑树的Java实现 2009-12-19 22:21 tcelvis
能不能把其他几个相关类的代码也给放出来?DefaultBSTree和BSTree等等,光看这个有些不明白。为什么RBnode中只定义parents而直接使用父类的left和right?据我所知BSTree的结点也应该有parents域才对。  回复  更多评论
  

# re: 红黑树的Java实现 2009-12-19 23:51 tcelvis
还有一个不太理解的地方。为什么你的每个子类都要定义一个<E extends Comparable<E>>?这实际上不是把RBTree定义的<E extends Comparable<E>>给隐藏了么?直接引用RBTree已经定义的E不可以么?  回复  更多评论
  

# re: 红黑树的Java实现 2010-07-25 15:26 姚朝文
别忘了,你现在写的东西,都是给国人看的多!不是对自己的英语很自信就拿来炫,最好给出中英注释!  回复  更多评论
  

# re: 红黑树的Java实现 2010-11-24 12:42 big
@姚朝文
连英文都不看你还写什么code, 回家洗洗睡吧, 人家欠你的吗?还好意思要中英注释, 莫名其妙。  回复  更多评论
  

# re: 红黑树的Java实现 2011-01-05 21:51 stxpascal
package algorithms.tree 这个包在哪啊?  回复  更多评论
  

# re: 红黑树的Java实现 2011-03-04 11:16 chs
你脑门被夹了吧,看不懂不要看,照你这么说你在中国,那你学英语干屁啊,都是21世纪的人,国家提倡学习英语,你还在这里给国人看。2B @姚朝文
  回复  更多评论
  

# re: 红黑树的Java实现[未登录] 2013-01-05 14:39 大大
干你妈比的,要么写中文注释,要么死回你妈比里去,会俩英文,拽尼玛腿啊  回复  更多评论
  

# re: 红黑树的Java实现 2014-02-02 16:47 new
删除部分的代码貌似不对啊。
如果删除的是一个左右子树都存在的节点,那么成分会先找到前序节点,并把cur指向该节点(该节点没有右子树存在)。
接下来进入判断,如果cur存在左子树,把左子树赋给cur的父节点。
问题在于被删除节点的父节点和cur之间没有了关联(没有设置)。
而且对于某些额情况,还会存在左子树作为了被删除节点的子树。例如,对于深度为2的满二叉树,对左1添加子节点之后,删除根节点的左节点。

请楼主再仔细验证一下。  回复  更多评论
  

# re: 红黑树的Java实现 2014-02-26 20:27 super fly
想问一下,这个是完整,直接能用的代码吗???好像是不怎么行耶?  回复  更多评论
  

# re: 红黑树的Java实现 2014-02-26 20:38 super fly
怎么找到这个DefaultBSTree和BSTree啊?@new  回复  更多评论
  


只有注册用户登录后才能发表评论。


网站导航:
博客园   IT新闻   Chat2DB   C++博客   博问