红黑树(下)

本文是红黑树系列文章的第三篇,前两篇分别介绍了2-3树和红黑树常用操作的理论,本文主要介绍红黑树的实现。

/**
 * 红黑树类
 * @author Administrator
 *
 */
public class RedBlackTree<T extends Comparable> {

    //定义红黑树的颜色
    private static final boolean RED = true;
    private static final boolean BLACK = false;
    /**
     * 节点类
     * @author Administrator
     *
     */
    static class Node{
        Object data;
        Node parent,left,right;
        //节点的默认颜色是黑色
        boolean color = BLACK;
        public Node(Object data, Node parent, Node left, Node right) {
            this.data = data;
            this.parent = parent;
            this.left = left;
            this.right = right;
        }
        @Override
        public String toString() {
            return "Node [data=" + data + ", parent=" + parent + ", left=" + left + ", right=" + right + ", color="
                    + color + "]";
        }
        @Override
        public boolean equals(Object obj) {
            if(this == obj){
                return true;
            }
            if(obj.getClass() == Node.class){
                Node target = (Node) obj;
                return data.equals(target.data) &&
                        parent ==(target.parent) &&
                        left == (target.left) &&
                        right == (target.right) &&
                        color == (target.color);
            }
            return false;
        }

    }
    //根节点
    private Node root;
    public RedBlackTree() {
        root = null;
    }
    public RedBlackTree(T data) {
        this.root = new Node(data, null, null, null);
    }
    /**
     * 添加节点
     * @param ele
     */
    public void add(T ele){
        //如果根节点为空
        if(root == null){
            root = new Node(ele, null, null, null);
        }
        else{
            Node current = root;
            Node parent = null;
            int cmp ;
            //搜索合适的叶子节点,以该节点为父节点添加合适的子节点
            do
            {
                parent = current;
                cmp = ele.compareTo(current.data);
                //如果新节点大于当前节点
                if(cmp > 0){
                    //以右子节点为当前节点
                    current = current.right;
                }
                //如果新节点小于当前节点
                if(cmp < 0){
                    current = current.left;
                }
                else{
                    current.data = ele;
                }
            }while(current != null);
            //创建新节点
            Node newNode = new Node(ele, parent, null, null);
            if(cmp > 0){
                //新节点作为父节点的右孩子
                parent.right = newNode;
            }
            else{
                //新节点作为父节点的右孩子
                parent.left = newNode;
            }
            //维护修复红黑树
            fixAfterInsertion(newNode);
        }
    }
    /**
     * 插入新节点后维护修复红黑树
     * @param newNode 新插入的节点
     */
    private void fixAfterInsertion(Node x) {

        x.color = RED;
        //知道x的父节点不是根节点且x的父节点是红色
        while(x != null && x != root && x.parent.color == RED){
            //x的父节点是其父节点的左子节点
            if(parentOf(x) == leftOf(parentOf(parentOf(x)))){
                //获取父节点的兄弟节点
                Node y = rightOf(parentOf(parentOf(x)));
                //如果x的父节点的兄弟节点是红色
                if(colorOf(y) == RED){
                    //将x的父节点设为黑色
                    setColor(parentOf(x),BLACK);
                    //将x的父节点的兄弟节点设为黑色
                    setColor(y, BLACK);
                    //将x的父节点的父节点设为红色
                    setColor(parentOf(parentOf(x)), RED);
                    x = parentOf(parentOf(x));
                }
                //如果x的父节点的兄弟节点是黑色的
                else{
                    //如果x是父节点的右子节点
                    if(x == rightOf(parentOf(x))){
                        //将x的父节点设为x
                        x = parentOf(x);
                        rotateLeft(x);
                    }
                    //把x的额父节点设为黑色
                    setColor(parentOf(x), BLACK);
                    //把x的父节点的父节点设为红色
                    setColor(parentOf(parentOf(x)), RED);
                    rotateRight(parentOf(parentOf(x)));
                }
            }
            //x的父节点是其父节点的右子节点
            else{
                //获取父节点的兄弟节点
                Node y = leftOf(parentOf(parentOf(x)));
                //如果x的父节点的兄弟节点为红色
                if(colorOf(y) == RED){
                    //将x的父节点设为黑色
                    setColor(parentOf(x),BLACK);
                    //将x的父节点的兄弟节点设为黑色
                    setColor(y, BLACK);
                    //将x的父节点的父节点设为红色
                    setColor(parentOf(parentOf(x)), RED);
                    x = parentOf(parentOf(x));
                }
                //如果x的父节点的兄弟节点是黑色的
                else{
                    //如果x是父节点的左子节点
                    if(x == leftOf(parentOf(x))){
                        //将x的父节点设为x
                        x = parentOf(x);
                        rotateRight(x);
                    }
                    //把x的额父节点设为黑色
                    setColor(parentOf(x), BLACK);
                    //把x的父节点的父节点设为红色
                    setColor(parentOf(parentOf(x)), RED);
                    rotateLeft(parentOf(parentOf(x)));
                }
            }
        }
        root.color = BLACK;
    }
    /**
     * 右旋
     * @param parentOf
     */
    private void rotateRight(Node p) {
        if(p != null){
            //求得左右左右子节点
            Node l = p.left;
            Node q = l.right;
            //将l的右子节点链接到p的左子节点
            p.left = q;
            //让l的you子节点的parent指向p节点
            if(q != null){
                q.parent = p;
            }
            l.parent = p.parent;
            //如果p已经是根节点
            if(p.parent == null){
                root = l;
            }
            //如果p是其父节点的you子节点
            else if(p.parent.left == p){
                //将r设为x的父节点的you子节点
                p.parent.right = l;
            }else{
                //将l设为p的父节点的zuo子节点
                p.parent.left = l;
            }
            l.right = p;
            p.parent = l;
        }

    }
    /**
     * 左旋
     * @param x
     */
    private void rotateLeft(Node x) {
        if(x != null){
            //求得左右左右子节点
            Node r = x.right;
            Node q = r.left;
            //将r的左子节点链接到x的右子节点
            x.right = q;
            //让r的左子节点的parent指向x节点
            if(q != null){
                q.parent = x;
            }
            r.parent = x.parent;
            //如果x已经是根节点
            if(x.parent == null){
                root = r;
            }
            //如果x是其父节点的左子节点
            else if(x.parent.left == x){
                //将r设为x的父节点的左子节点
                x.parent.left = r;
            }else{
                //将r设为x的父节点的右子节点
                x.parent.right = r;
            }
            r.left = x;
            x.parent = r;
        }
    }
    /**
     * 为指定节点设置颜色
     * @param p 指定节点
     * @param c 颜色
     */
    private void setColor(Node p, boolean c) {
        if(p != null){
            p.color = c;
        }
    }
    /**
     * 获取指定节点的颜色
     * @param y 指定节点
     * @return 返回指定节点的颜色
     */
    private boolean colorOf(Node y) {
        return (y == null ? BLACK : y.color);
    }
    /**
     * 获取指定节点的右子节点
     * @param p 指定节点
     * @return 返回自定节点的右子节点
     */
    private Node rightOf(Node p) {
        return (p == null) ? null : p.right;
    }
    /**
     * 获取指定节点的左子节点
     * @param p 指定节点
     * @return 返回自定节点的左子节点
     */
    private Node leftOf(Node p) {
        return (p == null) ? null : p.left;
    }
    /**
     * 获取指定节点的父节点
     * @param x 指定节点
     * @return 返回自定节点的父节点
     */
    private Node parentOf(Node x) {
        return (x == null ? null : x.parent);
    }
    /**
     * 删除节点
     * @param ele 要删除的节点的值
     */
    public void remove(T ele){
        //获取要删除的节点
        Node target = getNode(ele);
        //如果被删除的节点的左右子树都不为空
        if(target.left != null && target.right != null){
            //找到target中序便利的前一个节点,用s表示
            Node s = target.left;
            //搜索左子树中的最大节点
            while(s.right != null){
                s = s.right;
            }
            //用s代替p节点
            target.data = s.data;
            target = s;
        }
        //开始修复替换节点,如果该节点不为null
        Node replacement = (target.left != null ? target.left : target.right);
        if(replacement != null){
            //让replacement的parent指向target的parent
            replacement.parent = target.parent;
            //如果target的parent为null,则target为根节点
            if(target.parent == null){
                root = replacement;
            }
            //如果target是其父节点的左子孩子
            else if(target == target.parent.left){
                //让target的父节点的左子孩子指向replacement
                target.parent.left = replacement;
            }
            //如果target是其父节点的右子孩子
            else{
                //让target的父节点的右子孩子指向replacement
                target.parent.right = replacement;
            }
            //彻底删除target节点
            target.parent = target.left = target.right = null;
            //修复红黑树
            if(target.color == BLACK){
                fixAfterDeletion(replacement);
            }
        }
        //target本身为根节点
        else if(target.parent == null){
            root = null;
        }
        else{
            //target没有子节点,把它当成虚的替换节点
            //修复红黑树
            if(target.color == BLACK){
                fixAfterDeletion(target);
            }
            if(target.parent != null){
                //如果target是其父节点的左子节点
                if(target == target.parent.left){
                    target.parent.left = null;
                }
                //如果target是其父节点的右子节点
                if(target == target.parent.right){
                    target.parent.right = null;
                }
                //将target的parent置为null
                target.parent = null;
            }
        }
    }
    /**
     * 杀出节点后修复红黑树
     * @param replacement
     */
    private void fixAfterDeletion(Node x) {
        //直到x不是根节点且x的颜色是黑色
        while(x != root && colorOf(x) == BLACK){
            //如果x是其父节点的左子节点
            if(x == leftOf(parentOf(x))){
                //获取x节点的兄弟节点
                Node sid = rightOf(parentOf(x));
                //如果sid节点是红色的
                if(sid.color == RED){
                    //将sid设为黑色
                    setColor(sid, BLACK);
                    //将x的父节点设为红色
                    setColor(parentOf(x), RED);
                    rotateLeft(parentOf(x));
                    //再次将sid设为x的父节点的右子节点
                    sid = rightOf(parentOf(x));
                }
                //如果sid的两个子节点均为黑色
                if(colorOf(leftOf(sid)) == BLACK && colorOf(rightOf(sid)) == BLACK){
                    //将sid设为红色
                    setColor(sid, BLACK);
                    //让x等于它的父节点
                    x = parentOf(x);
                }
                else{
                    //如果sid只有右子节点是黑色的
                    if(colorOf(rightOf(sid)) == BLACK){
                        //将sid的左子节点设为黑色
                        setColor(leftOf(sid), BLACK);
                        //将sid设为红色
                        setColor(sid, RED);
                        rotateRight(sid);
                        sid = rightOf(parentOf(sid));
                    }
                    //设置sid的颜色与x的父节点的颜色相同
                    setColor(sid, colorOf(parentOf(x)));
                    //将x的父节点设为黑色
                    setColor(parentOf(x), BLACK);
                    //将sid的右子节点设为黑色
                    setColor(rightOf(sid), BLACK);
                    rotateLeft(parentOf(x));
                    x = root;
                }
            }else{
                //如果x是其父节点的右子节点
                //获取x的兄弟节点
                Node sid = leftOf(parentOf(x));
                //如果sid的颜色是红色的
                if(colorOf(sid) == RED){
                    //将sid点的颜色设为黑色
                    setColor(sid, BLACK);
                    //将sid的父节点设为红色
                    setColor(parentOf(sid),RED);
                    rotateRight(parentOf(x));
                    sid = leftOf(parentOf(x));
                }
                //如果sid的两个节点都是黑色
                if(colorOf(leftOf(sid)) == BLACK && colorOf(rightOf(sid)) == BLACK){
                    //将sid设为红色
                    setColor(sid, BLACK);
                    //让x等于它的父节点
                    x = parentOf(x);
                }else{
                    //如果sid只有左子节点是黑色的
                    if(colorOf(leftOf(sid)) == BLACK){
                        //将sid的右子节点设为黑色
                        setColor(rightOf(sid), BLACK);
                        //将sid设为红色
                        setColor(sid, RED);
                        rotateLeft(sid);
                        sid = leftOf(parentOf(sid));
                    }
                    //设置sid的颜色与x的父节点的颜色相同
                    setColor(sid, colorOf(parentOf(x)));
                    //将x的父节点设为黑色
                    setColor(parentOf(x), BLACK);
                    //将sid的右子节点设为黑色
                    setColor(leftOf(sid), BLACK);
                    rotateLeft(parentOf(x));
                    x = root;
                }
            }
        }
        setColor(x, BLACK);
    }
    /**
     * 根据节点的值获取节点
     * @param ele 节点的值
     * @return
     */
    public Node getNode(T ele) {
        // 从根节点开始搜索
        Node p = root;
        while(p != null){
            int cmp = ele.compareTo(p.data);
            if(cmp > 0){
                p = p.right;
            }else if(cmp < 0){
                p = p.left;
            }else{
                return p;
            }
        }
        return null;
    }
}
参考文献
  1. 《算法》
  2. 《java突破程序员基本功的16课》
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值