数据结构(7)之红—黑树

概念
红黑树是一种自平衡二叉查找树,是在计算机科学中用到的一种数据结构,典型的用途是实现关联数组。它是在1972年由Rudolf Bayer发明的,他称之为"对称二叉B",它现代的名字是在Leo J. Guibas Robert Sedgewick 1978年写的一篇论文中获得的。它是复杂的,但它的操作有着良好的最坏情况运行时间,并且在实践中是高效的: 它可以在O(log n)时间内做查找,插入和删除,这里的n 是树中元素的数目。
  红黑树是一种很有意思的平衡检索树。它的统计性能要好于平衡二叉树(有些书籍根据作者姓名,Adelson-VelskiiLandis,将其称为AVL-),因此,红黑树在很多地方都有应用。在C++ STL中,很多部分(目前包括set,multiset, map, multimap)应用了红黑树的变体(SGI STL中的红黑树有一些变化,这些修改提供了更好的性能,以及对set操作的支持)

性质
  红黑树是每个节点都带有颜色属性的二叉查找树,颜色或红色或黑色。在二叉查找树强制一般要求以外,对于任何有效的红黑树我们增加了如下的额外要求:
  性质1. 节点是红色或黑色。
  性质2. 根是黑色。
  性质3. 所有叶子都是黑色(叶子是NIL节点)。
  性质4. 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
  性质5. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。
  
  这些约束强制了红黑树的关键性质: 从根到叶子的最长的可能路径不多于最短的可能路径的两倍长。结果是这个树大致上是平衡的。因为操作比如插入、删除和查找某个值的最坏情况时间都要求与树的高度成比例,这个在高度上的理论上限允许红黑树在最坏情况下都是高效的,而不同于普通的二叉查找树。
  要知道为什么这些特性确保了这个结果,注意到属性4导致了路径不能有两个毗连的红色节点就足够了。最短的可能路径都是黑色节点,最长的可能路径有交替的红色和黑色节点。因为根据属性5所有最长的路径都有相同数目的黑色节点,这就表明了没有路径能多于任何其他路径的两倍长。

一种红黑树的实现方法:

/**
*
红黑树的实现
**/

public class RBTreeTest<E extends Comparable<E>> {
    static enum Color {
        BLACK, RED
    }
   
    static class RBPrinter {
        public static void visitNode(RBNodenode) {
            RBNode n =node;
            if (n !=null)
               System.out.print(n.key + "("
                       + (n.color == Color.RED ? "RED" : "BLACK")
                       + "),");
        }
    }

    static class RBNode<E extendsComparable<E>> {
        E key;

        RBNode<E>left, right;

        RBNode<E>parent;

        Color color;

       RBNode(RBNode<E> p, E key, Color color) {
            this.key =key;
            this.color =color;
            this.parent= p;
            this.left =null;
            this.right =null;
        }
    }

    private RBNode<E> root;

    public RBTreeTest() {
        root = null;
    }

    public boolean isEmpty() {
        return root == null;
    }

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

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

    public final boolean contains(E ele) {
        RBNode<E> tmp = root;
        int cmp = -1;
        while (tmp != null) {
            cmp =ele.compareTo(tmp.key);
            if (cmp <0) {
               tmp = tmp.left;
            } else if(cmp > 0) {
               tmp = tmp.right;
            } else {
               return true;
            }
        }
        return false;
    }

    public final boolean delete(E ele) {
        RBNode<E> cur;
        int cmp;
        if (root == null)
            returnfalse;
        cur = root;
        while (cur != null && (cmp =ele.compareTo(cur.key)) != 0) {
            if (cmp <0)
               cur = cur.left;
            else
               cur = cur.right;
        }
        if (cur == null) {
            returnfalse;
        }
        if ((cur.left) != null &&(cur.right) != null) {
           RBNode<E> prev = cur.left;
            while((prev.right) != null) {
               prev = prev.right;
            }
            cur.key =prev.key;
            cur = prev;
        }
        if ((cur.left) != null) {
            if (cur ==root) {
               root = cur.left;
               root.color = Color.BLACK;
               return true;
            }
            if(cur.parent.left == cur) {
               cur.parent.left = cur.left;
               cur.left.parent = cur.parent;
            } else {
               cur.parent.right = cur.left;
               cur.left.parent = cur.parent;
            }
            if(cur.color == Color.BLACK) {
               cur.left.color = Color.BLACK;
            }
        } else if ((cur.right) != null) {
            if (cur ==root) {
               root = cur.right;
               root.color = Color.BLACK;
               return true;
            }
            if(cur.parent.left == cur) {
               cur.parent.left = cur.right;
               cur.right.parent = cur.parent;
            } else {
               cur.parent.right = cur.right;
               cur.right.parent = cur.parent;
            }
            if(cur.color == Color.BLACK) {
               cur.right.color = Color.BLACK;
            }
        } else {
            if (cur ==root) {
               root = null;
               return true;
            }
           RBNode<E> todo;
            if(cur.parent.left == cur) {
               todo = null;
               cur.parent.left = todo;
            } else {
               todo = null;
               cur.parent.right = todo;
            }
            if(cur.color == Color.BLACK) {
               fixupDoubleBlack(todo);
            }
        }
        return true;
    }

    private final voidfixupDoubleBlack(RBNode<E> cur) {
        RBNode<E> sibling;
        RBNode<E> p;

        while (cur !=root) {
            p =cur.parent;
            if (p.left== cur) {
               sibling = p.right;
               if (sibling.color == Color.RED) {
                   rotateLeft(p);
                   p.color = Color.RED;
                   sibling.color = Color.BLACK;
               } else {
                   if (sibling.right.color == Color.RED) {
                       rotateLeft(p);
                       p.color = Color.BLACK;
                       sibling.right.color = Color.BLACK;
                       return;
                   } else if (sibling.left.color == Color.RED) {
                       rotateRight(sibling);
                       sibling.color = Color.RED;
                       sibling.parent.color = Color.BLACK;
                   } else {
                       sibling.color = Color.RED;
                       if (p.color == Color.BLACK) {
                           cur = p;
                       } else {
                           p.color = Color.BLACK;
                           return;
                       }
                   }
               }
            } else {
               sibling = p.left;
               if (sibling.color == Color.RED) {
                   rotateRight(p);
                   p.color = Color.RED;
                   sibling.color = Color.BLACK;
               } else {
                   if (sibling.left.color == Color.RED) {
                       rotateRight(p);
                       sibling.color = p.color;
                       p.color = Color.BLACK;
                       sibling.left.color = Color.BLACK;
                       return;
                   } else if (sibling.right.color == Color.RED) {
                       rotateLeft(sibling);
                       sibling.color = Color.RED;
                       sibling.parent.color = Color.BLACK;
                   } else {
                       sibling.color = Color.RED;
                       if (p.color == Color.BLACK) {
                           cur = p;
                       } else {
                           p.color = Color.BLACK;
                           return;
                       }
                   }
               }
            }
        }
    }

    public final void insert(E ele) {
        if (root == null) { //
添加根节点
            root = newRBNode<E>(null, ele, Color.BLACK);
            return;
        } else { //
将该节点添加到合适的叶子节点的位置
           RBNode<E> parent = null;
           RBNode<E> cur = root;
            int cmp =-1;
            while (cur!= null && (cmp = ele.compareTo(cur.key)) != 0) {
               parent = cur;
               if (cmp < 0)
                   cur = cur.left;
               else
                   cur = cur.right;
            }
            if (cmp ==0) { //
不能添加相同的元素
               throw new IllegalArgumentException(
                       "can't insert duplicate key!");
            }
            cur = newRBNode<E>(parent, ele, Color.RED);
            if (cmp <0) { //
添加为左孩子
               parent.left = cur;
            } else { //
添加为右孩子
               parent.right = cur;
            }

           insertFixup(cur); // 调整各个节点
        }
    }

    private final voidinsertFixup(RBNode<E> cur) {
        RBNode<E> p, g;
        while (cur != root &&cur.color == Color.RED) {
            p =cur.parent;
            if (p.color== Color.BLACK) {
               return;
            }
            g =p.parent;
            if (p ==g.left) { // p
g的左子树
               RBNode<E> uncle = g.right;
               if (uncle != null && uncle.color == Color.RED) {
                   g.color = Color.RED;
                   uncle.color = p.color = Color.BLACK;
                   cur = g;
               } else {
                   if (cur == p.right) {
                       cur = rotateLeft(p);
                       cur = cur.left;
                   }
                   cur = rotateRight(g);
                   cur.color = Color.BLACK;
                   cur.left.color = cur.right.color = Color.RED;
               }
            } else { // p
g的右子树
               RBNode<E> uncle = g.left;
               if (uncle != null && uncle.color == Color.RED) {
                   g.color = Color.RED;
                   uncle.color = p.color = Color.BLACK;
                   cur = g;
               } else {
                   if (cur == p.left) {
                       cur = rotateRight(p);
                       cur = cur.right;
                   }
                   cur = rotateLeft(g);
                   cur.color = Color.BLACK;
                   cur.left.color = cur.right.color = Color.RED;
               }
            }
        }
        root.color = Color.BLACK;
    }

    /*
     *     gr          gr           gr  
     *    /           /             /  
     *   p                           ch
     *   / \   =>   p ch   =>   /\         ch
绕着父节点p左旋(即将父节点p和它的右孩子转换角色)
     * 1 ch      /      \         p    3
     *     / \    1   2    3      / \
     *   2   3                  1    2
     */

    private final RBNode<E> rotateLeft(RBNode<E> p){
        RBNode<E> gr =p.parent;//grandfather
        RBNode<E> ch =p.right;    //children
        p.right = ch.left;
        if (ch.left != null) {
           ch.left.parent = p;
        }
        ch.left = p;
        p.parent = ch;
   
        if (gr != null) {    //p
不是root节点
            if (gr.left== p)    //
如果pgr的左孩子
               gr.left = ch;
           else                //p
gr的右孩子
               gr.right = ch;
        } else{            //p
root节点
           root = ch;
        }
        ch.parent = gr;
        return ch;
    }
   
   /*
     *      gr          gr           gr  
     *     /            /              /  
     *    p                          ch
     *    / \   =>  ch p   =>   /\         ch
绕着父节点p右旋(即将父节点p和它的左孩子转换角色)
     *   ch 3     /      \        1   p
     *   /\         1  2   3           / \
     * 1   2                        2   3
     */
    private final RBNode<E>rotateRight(RBNode<E> p) {
        RBNode<E> gr = p.parent;
        RBNode<E> ch = p.left;
        p.left = ch.right;
        if (ch.right != null) {
           ch.right.parent = p;
        }
        ch.right = p;
        p.parent = ch;
        if (gr != null) {
            if (gr.left== p)
               gr.left = ch;
            else
               gr.right = ch;
        } else {
            root = ch;
        }
        ch.parent = gr;
        return ch;
    }
   
    public void inOrder(){
        inOrder(root);
    }
   
    private void inOrder(RBNode<E> cur) {
        if(cur != null){
           inOrder(cur.left);
           RBPrinter.visitNode(cur);
           inOrder(cur.right);
        }
    }

    public static void main(String[] args) {
        java.util.Random ran = newjava.util.Random();
        RBTreeTest<Integer> rbt = newRBTreeTest<Integer>();
        int tmp = 0;
        for(int i=0;i<15;i++){
            tmp =ran.nextInt(1000);
            try{
               rbt.insert(tmp);
            } catch(IllegalArgumentException e){
               do{
                   tmp = ran.nextInt(1000);
               }while(rbt.contains(tmp));
               rbt.insert(tmp);
            }
           System.out.println(tmp);
        }
       
        System.out.print("\nInorderbegin:\n");
        rbt.inOrder();
        System.out.print("\nInorderend\n");
       
        rbt.delete(tmp);
       
        System.out.print("\nInorderbegin:\n");
        rbt.inOrder();
        System.out.print("\nInorderend\n");
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值