数据结构-红黑树

红黑树是AVL树的变种,对红黑树的操作最坏情况下花费O(logN)的时间。相较于AVL树,红黑树更能用一种非递归的方式实现插入。红黑树是非严格的平衡二叉树,而AVL树是严格的平衡二叉树。
红黑树具有以下特征:
1、每个节点要么是红色,要么是黑色。
2、根节点是黑色。
3、NULL节点为黑色。
4、如果节点是红色,那么子节点必须是黑色。
5、从一个节点到一个null引用的路径必须包含相同的黑色节点数。
接着来看一下如何插入数据:

自底向上的插入

为了维持第5个特点,所以插入的数据必然要是红色。
所谓自底向上的插入,就是先将红色节点插入到树中,再从插入点,逐步向上解决冲突。
①第一种情况:如果插入后,父节点是黑色,那么旧完成插入。
②第二次情况:如果插入后,父节点是红色,父节点的兄弟节点是黑色,那么进行一次单旋转或者之字形旋转,如下图所示。
这里写图片描述
③第三种情况:如果插入后,父节点和它的兄弟节点都是红色。(下图中双圆圈代表红色)加入我们要将79插入,那么我们将父节点和它的兄弟节点都变成黑色,这样保证了两边路径黑色节点的平和,祖父节点变成红色,这样保证了祖父节点和其兄弟节点路径上黑色节点数的一致。加入祖父节点的父节点是红色,那么将祖父节点的父节点的红色向上过滤。
这里写图片描述

自顶向下的插入

自顶向下的插入时在节点向下寻找插入点的过偶程中,保证父亲的兄弟节点不是红色的,这样就只需要进行一次单旋转或者之字形旋转。在向下的过程中,当看到有一个节点有两个红色儿子,那么将这两个红色儿子变成黑色,该节点变成红色。这样能保持该子树路径上的黑色节点和兄弟子树相同。如果该节点为根节点,那么该节点不需要变成红色。如果该节点的父亲节点也是红色,那么只需要通过旋转就能解除冲突,不需要将红色节点上滤,因为自顶向下的过程中已经保证了两个兄弟节点不可能都为红色。
这里写图片描述
插入代码
采用非递归形式插入

package com.creat.redblack;


/**
 * Created by WHZ on 2017/8/13 0013.
 */
public class RedBlackTree<E extends Comparable<? super E>>{
    private RedBlackNode<E> root;

    private static class RedBlackNode<E>{
        int color;
        E element;
        RedBlackNode<E> left;
        RedBlackNode<E> right;
        RedBlackNode<E> father;

        static final int BLACK = 1;
        static final int RED =  0;

        RedBlackNode(E element){
            this.element = element;
            this.father = null;
            this.left = null;
            this.right = null;
            this.color = RedBlackNode.RED;
        }

        RedBlackNode(E element, RedBlackNode<E> father){
            this.element = element;
            this.father = father;
            this.left = null;
            this.right = null;
            this.color = RedBlackNode.RED;
        }
        RedBlackNode(E element,RedBlackNode<E> father,int color){
            this.element = element;
            this.father = father;
            this.left = null;
            this.right = null;
            this.color = color;
        }
    }

    public void printTree(){
        printTree(root);
    }

    private void printTree(RedBlackNode<E> node){
        if(node != null){
            printTree(node.left);
            System.out.println(node.element+((node.color==1)?"黑色":"红色"));
            printTree(node.right);
        }
    }

    public void insert(E element){
        if(root == null){
            root = new RedBlackNode<E>(element,null,RedBlackNode.BLACK);
        }else {
            RedBlackNode<E> point = root;
            int compareResult = element.compareTo(point.element);
            while(compareResult != 0){
                if(isRed(point.left) && isRed(point.right)){
                    if(point == root){
                        point.left.color = RedBlackNode.BLACK;
                        point.right.color = RedBlackNode.BLACK;
                    }else {
                        point.color = RedBlackNode.RED;
                        point.left.color = RedBlackNode.BLACK;
                        point.right.color = RedBlackNode.BLACK;
                        if(point.father.color == RedBlackNode.RED){
                            rotate(point);
                        }
                    }
                }
                if(compareResult > 0 ){
                   if(point.right == null){
                       point.right = new RedBlackNode<E>(element,point);
                       if(point.color == RedBlackNode.RED){
                            rotate(point.right);
                       }
                       break;
                   }else {
                       point = point.right;
                       compareResult = element.compareTo(point.element);
                   }
                }else if (compareResult < 0){
                    if(point.left == null){
                        point.left = new RedBlackNode<E>(element,point);
                        if(point.color == RedBlackNode.RED){
                            rotate(point.left);
                        }
                        break;
                    }else {
                        point = point.left;
                        compareResult = element.compareTo(point.element);
                    }
                }else {
                    break;
                }

            }
        }
    }

    private void rotate(RedBlackNode<E> point) {
        RedBlackNode<E> father = point.father;
        RedBlackNode<E> grandfather = father.father;
        RedBlackNode<E> result = null;
        if(isLeftNode(father) && isLeftNode(point)){
            result = rotateWithLeftChild(grandfather);
        }else if(isRightNode(father) && isRightNode(point)){
            result = rotateWithRightChild(grandfather);
        }else if(isLeftNode(father) && isRightNode(point)){
            result = doubleWithLeftChild(grandfather);
        }else {
            result = doubleWithRightChild(grandfather);
        }
        if(grandfather == root){
            root = result;
        }else {
            if(isRightNode(result)){
                result.father.right = result;
            }else {
                result.father.left = result;
            }
        }
    }

    private RedBlackNode<E> rotateWithLeftChild(RedBlackNode<E> node){
        RedBlackNode<E> left = node.left;
        node.left = left.right;
        left.right = node;
        node.color = RedBlackNode.RED;
        left.color = RedBlackNode.BLACK;
        left.father = node.father;
        node.father = left;
        if(node.left != null){
            node.left.father = node;
        }
        return left;
    }

    private RedBlackNode<E> rotateWithRightChild(RedBlackNode<E> node){
        RedBlackNode<E> right = node.right;
        node.right = right.left;
        right.left = node;
        node.color = RedBlackNode.RED;
        right.color = RedBlackNode.BLACK;
        right.father = node.father;
        node.father = right;
        if(node.right != null){
            node.right.father = node;
        }
        return right;
    }

    private RedBlackNode<E> doubleWithLeftChild(RedBlackNode<E> node){
        node.left = rotateWithRightChild(node.left);
        return rotateWithLeftChild(node);
    }

    private RedBlackNode<E> doubleWithRightChild(RedBlackNode<E> node){
        node.right = rotateWithLeftChild(node.right);
        return rotateWithRightChild(node );
    }

    private boolean isRed(RedBlackNode<E> node){
        if(node == null){
            return false;
        }else if(node.color == RedBlackNode.RED){
            return true;
        }else {
            return false;
        }
    }
    private boolean isBlack(RedBlackNode<E> node){
        if(node == null){
            return true;
        }else if(node.color == RedBlackNode.BLACK){
            return true;
        }else {
            return false;
        }
    }
    private boolean isLeftNode(RedBlackNode<E> node){
        RedBlackNode<E> father = node.father;
        if(father == null){
            return false;
        }else {
            int compareResult = node.element.compareTo(father.element);
            if(compareResult < 0){
                return true;
            }else {
                return false;
            }
        }
    }
    private boolean isRightNode(RedBlackNode<E> node){
        RedBlackNode<E> father = node.father;
        if(father == null){
            return false;
        }else {
            int compareResult = node.element.compareTo(father.element);
            if(compareResult > 0){
                return true;
            }else {
                return false;
            }
        }
    }
}

测试结果:

package com.creat.redblack;

/**
 * Created by Administrator on 2017/8/13 0013.
 */
public class Client {

    public static void main(String[] args){
        RedBlackTree<Integer> tree = new RedBlackTree<Integer>();
        tree.insert(30);
        tree.insert(70);
        tree.insert(60);
        tree.insert(15);
        tree.insert(10);
        tree.insert(20);
        tree.insert(80);
        tree.insert(85);
        tree.insert(50);
        tree.insert(65);
        tree.insert(5);
        tree.insert(40);
        tree.insert(55);
        tree.insert(89);
        tree.insert(65);
        tree.printTree();
    }
}
5红色
10黑色
15黑色
20黑色
30红色
40红色
50黑色
55红色
60黑色
65红色
70黑色
80黑色
85黑色
89红色

自顶向下的删除

如果需要删除的节点有两个儿子或者只有一个右儿子,那么用右子树上最小的节点代替它,然后删除这个最小节点;
如果需要删除的节点有个左儿子,那么用左子树上最大的节点代替它,然后删除这个最大节点。
但是我们需要保证被删除的这个树叶为红色,所以我们采用一种办法要保证这个找到的树叶为红色。
X为当前指向的节点,我们要确保X是红的,先从根节点(个人理解:这个根节点应该是需要被替换节点的左子树或者右子树的根节点)向下遍历,如果X节点是红的,那么继续向下找,如果X节点不是红的,那么看他儿子是不是红的,如果儿子是红的,那么继续向下找,那么就行如下三种操作的其中一种:
这里写图片描述
接着继续寻找,最后找到需要被删除的树叶,因为之前的步骤确保了X为红色或者说X的儿子为红色,所以最后这个树叶可以被安全删除。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值