我的第一篇博客——红黑树的基本操作

RBTree是相对平衡的二叉查找树(bst),与AVL平衡二叉树相比,其”平衡“程度没有那么严格,因而在维护红黑树结构时需要较小的代价,总体性能较好(但是在有特殊查找要求时,考虑使用AVL_tree也是一个不错的选择。)下面我将写写RBTree的性质与基本操作:

首先来简单定义RBTree的节点,方便叙述

class RBTreeNode{
    int key;
    int color; //颜色值   1:BLACK 2:RED
    RBTreeNode p;  //父节点
    RBTreeNode left;  //左孩子
    RBTreeNode right; //右孩子
}

然后来了解RBTree的性质(专业定义请看算法导论红黑树章节)

1. root.color == BLACK  //根节点颜色为黑
2. node.color == BLACK OR RED   //每个节点的颜色为黑色或红色
3. if n.color == RED  //一个节点为红色,则两个孩子(非空的话)颜色为黑色
      n.left.color == BLACK  
      n.right.color == BLACK
4. node--->leaf 的路径上黑色节点数目相同 //任一节点到其叶子节点的路径上黑色节点的数目相同

由RBTree的性质,其颜色约束可以把RBTree的高度限制在log2^n以内,达到到降低时间复杂度的目的。

好了,现在就来看看基本的insert/delete/search 操作,因为RBTree是基于bst的,其search操作与bst的search一样,insert/delete也是在bst的insert/delete操作的基础上改进。由于intsert/delete时可能破坏RBTree的结构,所以需要维持其结构,一般通过改变相关节点的颜色或旋转来维护。

认识旋转操作:leftRotate(X)/rightRotate(Y)
这里写图片描述

分析insert操作(插入的节点颜色为红色,用n表示)
1. n == root //空树时插入,只破坏性质1
n.color = BLACK; return;
2. n != root //非空树时插入
a. if n.p == BLACK return; //性质1-4均没有被破坏
b. if n.p == RED //直接破坏了性质3,需要维护,在维护过程中只需关注n以及n的父亲·爷爷·叔叔,其中P:父亲 G:爷爷 U:叔叔,情况如下
这里写图片描述
由于前两种情况(LL/LR)与后两情况(RR/RL)镜面对称,讨论前两情况即可,代码实现时left与right互换即可。于是我们来看看前两情况的各种着色可能及应对策略

  1. P.color=BLACK; U.color=BLACK; G.color=RED; N=G;进入下一次迭代
    这里写图片描述
  2. rightRotate(G); P.color=BLACK; G.color=RED;进入下一次迭代
    这里写图片描述
  3. leftRotate(P); N<->P; rightRotate(G); P.color=BLACK; G.color=RED;进入下一次迭代

    这里写图片描述
    注意迭代终止条件为:上述1或2.a //while(n!=root && n.p.color==BLACK)

分析delete操作(删除节点为min,链接到n.p的节点为con)
1.删除点颜色为红色,return;
2.不为黑色则,把链接接上去的节点看成既具有自己的colo属性,也有一额外的“黑色”用来提高黑色节点数目,现在只要想办法把这个“黑色”转为某节点的color属性即可:
1. if con.color ==RED
con.color = BLACK; return;
2.关注con 及其父亲·叔叔·侄儿,情况如下:(灰色表示颜色不确定)
这里写图片描述
下面给出部分函数java代码实现:

class RBTreeNode{
    final static int BLACK = 1,RED = 0;
    int key;
    int color; //颜色值   1:BLACK 0:RED
    RBTreeNode p;  //父节点
    RBTreeNode left;  //左孩子
    RBTreeNode right; //右孩子
    RBTreeNode(int key,int color,RBTreeNode p,RBTreeNode left,RBTreeNode right){
        this.key = key;
        this.color = color;
        this.p = p;
        this.left = left;
        this.right = right;
    }
}

public class RBTree {
    private RBTreeNode root;
    RBTree(){ root = null;}
    void leftRotate(RBTreeNode x){//左旋转
        RBTreeNode y = x.right;
        if(x == root)
            root = y;
        else {
            if(x.p.left ==x) 
                x.p.left = y;
            else  
                x.p.right = y;
        }
        y.p = x.p;
        x.right = y.left;
        y.left = x;
        x.p = y;
        if(x.right != null)
            x.right.p = x;   
    }
    void rightRotate(RBTreeNode x){//右旋转
        RBTreeNode y = x.left;
        if(x == root)
            root = y;
        else {
            if(x.p.left ==x) 
                x.p.left = y;
            else  
                x.p.right = y;
        }
        y.p = x.p;
        x.left= y.right;
        y.right = x;
        x.p = y;
        if(x.left !=null)
            x.left.p = x;
    }
    void fixUpInsert(RBTreeNode n){   //插入后维持性质
        while(root != n && n.p.color == RBTreeNode.RED){
            if(n.p.p.left == n.p){  //LL LR
                if( n.p.right !=null &&
                    n.p.right.color == RBTreeNode.RED){
                    //情况2.1
                    n.p.color = RBTreeNode.BLACK;
                    n.p.color = RBTreeNode.BLACK;
                    n.p.p.color = RBTreeNode.RED;
                    n = n.p.p;
                 }
                 else {
                     if(n.p.right == n){
                         leftRotate(n.p);
                         n = n.left;
                     }
                     rightRotate(n.p.p);
                     n.p.color = RBTreeNode.BLACK;
                     n.p.right.color = RBTreeNode.RED;  
                 }
            }
            else{   //RR RL
                if( n.p.left !=null &&
                        n.p.left.color == RBTreeNode.RED){
                        n.p.color = RBTreeNode.BLACK;
                        n.p.color = RBTreeNode.BLACK;
                        n.p.p.color = RBTreeNode.RED;
                        n = n.p.p;
                     }
                     else {
                         if(n.p.left == n){
                             rightRotate(n.p);
                             n = n.right;
                         }
                         leftRotate(n.p.p);
                         n.p.color = RBTreeNode.BLACK;
                         n.p.left.color = RBTreeNode.RED;   
                     }
            }
        }
        root.color = RBTreeNode.BLACK;
    }
    void fixUpDelete(RBTreeNode n){ //删除后维持性质       
        //自己根据delete分析码出来吧
    }
    void insert(int key){  //插入操作
        if(root == null){  //空树时插入
            root = new RBTreeNode(key,RBTreeNode.BLACK,null,null,null);
        }
        else{  //非空树时插入
            RBTreeNode temRoot = root;
            RBTreeNode temRootPa =null;
            boolean markL = false;
            while(temRoot !=null){  //找到即将插入的位置
                markL = false;
                if(temRoot.key > key){
                    temRootPa = temRoot;
                    temRoot = temRoot.left;
                    markL = true; 
                }
                else {
                    temRootPa = temRoot;
                    temRoot = temRoot.right;
                }
            }
            if(markL){
                temRootPa.left = new RBTreeNode(key,RBTreeNode.RED,temRootPa,null,null);
                fixUpInsert(temRootPa.left);  //插入后维持性质
            }
            else {
                temRootPa.right = new RBTreeNode(key,RBTreeNode.RED,temRootPa,null,null);
                fixUpInsert(temRootPa.right);  //插入后维持性质
            }
        }
    }
    RBTreeNode getMin(RBTreeNode tem){
        while(tem.left != null)
            tem = tem.left;
        return tem;
    }
    void delete(int key){
            RBTreeNode temRoot = root;
            while(temRoot !=null){  //寻找要删除的节点
                if(temRoot.key > key)
                    temRoot = temRoot.left;
                else if(temRoot.key < key)
                    temRoot = temRoot.right;
                else break;
            }
            if(temRoot == null) return; //没有找到要删除的节点
            if(temRoot.left !=null && temRoot.right !=null){  //待删除节点有两个孩子
                RBTreeNode min = getMin(temRoot.right); //找到右子树中最小元素节点
                temRoot.key = min.key; //把待删除点转移到右子树中最小元素节点
                if(min.p.right == min) min.p.right = min.right;  //删除min节点
                else min.p.left = min.right;    
                fixUpDelete(min.right);  //删除后维持性质
            }
            else {
                RBTreeNode con = (temRoot.left != null ? temRoot.left : temRoot.right);
                //确定连接上去的节点
                if(temRoot ==root) //待删点为root
                    root = con;
                else{


                    if(temRoot.p.left == temRoot)
                    temRoot.p.left =con;
                    else temRoot.p.right = con;    
                }
                fixUpDelete(con);   //删除后维持性质
            }       
    }
}

h

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值