红黑树(3)残疾版红黑树新增实现

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/mottohlm/article/details/81604507

为什么说是残疾版呢,因为标准的红黑树是是三个值在一层,也就是父节点的左右分支节点都可以是红,但在此,我规定了只有左分支为红,也就是规定了最多只有两个值在一层。这样能减少很多修复平衡判断条件。在此我以实现简化版的treeMap 为例。

新增节点的第一步就是找出节点将要加入的位置,然后才修复平衡。

节点类的定义:

package hlm.com.treemap;

/**
* 节点:
* value 存值
* left 左子节点
* right 右子节点
* father 父节点(父节点为空,那表明该节点是根节点)
* color 颜色,
*/
public class Node {

private Object key ;
private Object value ;
private boolean color ;
private Node left ;
private Node right ;
private Node parent ;

public static final boolean BLANK = false ;
public static final boolean RED = true ;
public static final boolean LEFT = false ;
public static final boolean RIGHT = true ;

public Node() { }

public Node(Object key, Object value) {
this.key = key;
this.value = value;
this.color = BLANK ;
}

public Node(Object key, boolean color, Node left, Node right, Node parent) {
this.key = key;
this.color = color;
this.left = left;
this.right = right;
this.parent = parent;
}

public Object getValue() {
return value;
}

public void setValue(Object value) {
this.value = value;
}

public Node(Object key) {
this.key = key;
}

public Object getKey() {
return key;
}

public void setKey(Object key) {
this.key = key;
}

public boolean getColor() {
return color;
}

public void setColor(boolean color) {
this.color = color;
}

public Node getLeft() {
return left;
}

public void setLeft(Node left) {
this.left = left;
}

public Node getRight() {
return right;
}

public void setRight(Node right) {
this.right = right;
}

public Node getParent() {
return parent;
}

public void setParent(Node parent) {
this.parent = parent;
}

@Override
public String toString(){
return "k:"+ this.key+";v:"+this.value;
}
}

TreeMap 类的其他信息

public class MyTreeMap {

Logger log = LoggerFactory.getLogger(MyTreeMap.class) ;

/*** 根节点*/
private Node root ;

/*** 元素个数*/
private transient int size ;

}

入口 put 方法

/**
     * 添加k-v方法
     * @param k
     * @param v
     * @return
     */
    public Object put(Object k ,Object v){

        Node node = new Node(k , v);

        //没有根那么传进来的就是根
        if(root == null){
            root = node ;
            size ++ ;
            return root.getKey();
        }

       return addRedBlankNode(root , node);
    }

插入节点方法 addRedBlankNode

 /**
     * 按红黑树的方式添加节点
     * @param root
     * @param node
     * @return
     */
    private Object addRedBlankNode(Node root ,Node node){
        //起点不存在,那么返回null
        if(root == null ){
            return null ;
        }
        //插入节点为空,那无法插入
        if(node == null ){
            return null ;
        }

        Object targetKey = node.getKey();
        int tarint = hash(targetKey);
        Object rootKey = root.getKey();
        int rootint = hash(rootKey);
        //相等,刚覆盖更新
        if(tarint == rootint){
            root.setValue(node.getValue());
            return node.getValue();
        }
        //小于,左分支
        if(tarint < rootint){
            //存在左子节点时,递归检索进去
            if(root.getLeft() != null){
                return addRedBlankNode(root.getLeft() , node);
            }else{
                root.setLeft(node);
                node.setParent(root);

            }
        }

        //大于,右分支(由于只构建2-3树,所以添加右分支)
        if(tarint > rootint){
            //存在右子节点时,递归检索进去
            if(root.getRight() != null){
                return addRedBlankNode(root.getRight() , node);
            }else{
                root.setRight(node);
                node.setParent(root);
            }
        }

        //修复平衡
        fixBalance(node);
        size ++ ;
        return node.getKey();

    }

插入节点其实很简单,一路判断下去直到有位置即可

最后是修复平衡方法 fixBalance 。这个才是主角。

/**
     * 调整树结构及按需重新着色
     * @param node
     */
    private void fixBalance(Node node){
        //第一种情况,到顶了,node就是根了,那么要考虑把node的颜色变黑,
        if(node.getParent() == null){
            node.setColor(Node.BLANK);
        }
        //左支
       else if(Node.LEFT == checkLR(node,node.getParent())){
            //父节点为黑时,如果无左子节点或左子节点为黑,直接颜色置为红
            if(Node.BLANK == node.getParent().getColor() && (
                    (node.getLeft() !=null && node.getLeft().getColor()==Node.BLANK)
                            ||node.getLeft() == null)){
                node.setColor(Node.RED);
            }
            //父节点为黑时,但其左子节点为红,由于不能连续两红
            else if(Node.BLANK == node.getParent().getColor() &&
                    node.getLeft() !=null && node.getLeft().getColor()==Node.RED ){
                node.getLeft().setColor(Node.BLANK);
                turnRight(node);
                fixBalance(node);

            }
            //父节点为红时,其祖父节点是一定存在的
            //此时父节点那一层肯定是满的,只有进行变换了,看情况如何变换
            else if(Node.RED == node.getParent().getColor()){
                    Node root = node.getParent();
                    root.setColor(Node.BLANK);
                    turnRight(root);
                    fixBalance(root);
            }


        }

        //右支 (想办法变为左支)
        else if(Node.RIGHT == checkLR(node,node.getParent())){
            Node root = node.getParent();
            if(node.getLeft()==null ||node.getLeft().getColor() == Node.BLANK){
                if(root.getColor() == Node.RED){
                    turnLeft(node);
                    fixBalance(node);
                }else{
                    turnLeft(node);
                    fixBalance(root);
                }

            }
             else{
                node.getLeft().setColor(Node.BLANK);
                turnRight(node.getLeft());
                turnLeft(node.getLeft());
                fixBalance(node.getLeft());

            }
        }

    }

猜你喜欢

转载自blog.csdn.net/mottohlm/article/details/81604507