RB_TREE 红黑树插入及删除

注:文中所说旋转的说法:a绕b左(右)旋,指的是旋转前b 是a 的父节点,旋转后 b是a 的左(右)子节点

红黑树性质:

	* 1、所有节点要么为黑色,要么为红色
	* 2、根节点为黑色
	* 3、所有叶子节点为黑色(null视为叶子节点)
	* 4、红色节点的子节点为黑色
	* 5、对每个节点,从其到达叶子的所有路径中黑色节点个数相同

红黑树插入:

* 向红黑树中插入一个节点后可能会出现的情况(其中新节点记为红色,先将新节点插入到叶节点位置,此时可能破坏红黑树性质,执行fixRBTree函数)
* (插入过程默认原树已经满足红黑树性质,部分地方未做异常校验,如果树不满足红黑树性质,可能会出异常)
* fixRBTree(z)
* _ 情况1z为根节点:将z.color设置为black,满足红黑树性质,结束
* _ 情况2z的父节点为黑色,满足红黑树性质,结束
* _ 情况3z的父节点为红色,叔节点为红色,祖父节点为黑色:设置父、叔节点为黑色、祖父节点为红色,再令z指向祖父节点,递归fixRBTree(z),然后返回
* _ 
* _ 情况4z的父节点为红色,叔节点为黑色,祖父节点为黑色
* _    情况4.1 z的父节点为祖父节点的左孩子
* _        情况4.1.1 z为父节点的右孩子:zz的父节点左旋(z的父节点变成z的左子节点),令z指向z的左子节点=》情况4.1.2
* _        情况4.1.2 z为父节点的左孩子:将z的父节点、祖父节点变色,使z的父节点绕z的祖父节点右旋(此时,父节点为黑色,满足情况2,结束)
* _ 
* _    情况4.2 z的父节点为祖父节点的右孩子
* _        情况4.2.1 z为父节点的左孩子:zz的父节点右旋(z的父节点变成z的右子节点),令z指向z的右子节点=》情况4.2.2
* _        情况4.2.2 z为父节点的右孩子:将z的父节点、祖父节点变色,使z的父节点绕z的祖父节点左旋(此时,父节点为黑色,满足情况2,结束)
*
* _ 
* 分析:情况124.x均为结束情况。只有情况3递归调用函数,而且递归的过程中z向上移动两级,因此z向上的复杂度为 O(lgn)
* 分析:有旋转转的地方只有情况4.x,且无论哪次到情况4.x,最多旋转两次就结束
* 分析:因此,插入节点复杂度为:将z插入叶子节点的复杂度O(lgn) + 递归复杂度 O(lgn) + 旋转复杂度O(1)  =  O(lgn)

依次向红黑树中插入1-9过程










红黑树删除:

 * 结论1:若z 有且仅有一个非空子节点,那么z 必为黑色,且子节点为红色,且子节点只有一层
 * <p>
 * 情况1 z.left  z.right 均不为空,此时找到 z 的后继节点,记为zNext(必无左子节点),将zNextz替换,此时删除z即可(此时z无左节点,转入情况34 * 情况2 z.left 不为空      (根据结论1z为黑色,且z.left  为红色,且z.left  无子节点)此时直接用z.left  替换掉z,并将z.left  染黑
 * 情况3 z.right 不为空     (根据结论1z为黑色,且z.right 为红色,且z.right 无子节点)此时直接用z.right 替换掉z,并将z.right 染黑
 * 情况4 z.left z.right均为空  fixup

删除时修正:

* 修复红黑树:
* 
* 情况1 x x.parent 左子节点
* _    情况1.1 x 兄弟节点为红色(此时父节点必为黑,x兄弟节点的两子节点为黑):兄弟节点置黑,父节点置红,兄弟节点绕父节点左旋(x兄弟节点的左节点变为x新的兄弟节点)。此时转为情况1.2
* _    情况1.2 x 兄弟节点为黑色 
* _        情况1.2.1 x 的兄弟节点左右孩子均为黑色:将x兄弟节点置红,x指向x 的父节点
* _        情况1.2.2 x 的兄弟节点仅右孩子节点为黑色:将x兄弟节点置红,x兄弟节点左孩子置黑,将x.brother.left x.brother右旋。(转入情况1.2.3* _        情况1.2.3 x 的兄弟节点仅左孩子节点为黑色:x兄弟节点置红,x父节点置黑,将x 节点,将x.brother x.parent 左旋(x = root结束)
* _
* 情况2 x x.parent 右子节点(情况同上,左右相反)

实现(代码中有详细注释。可以插入、删除。可通过 前、中、后序遍历来验证):代码GitHub地址
import java.util.Scanner;

public class RB_TREE {
    
    private Node root = null;
    
    public RB_TREE() {
        
    }
    
    //TEST
    public static void main(String[] args) {
        
        RB_TREE  rbtree = new RB_TREE();
    
        Scanner sc = new Scanner(System.in);
        int oper = 0;
        while(true){
            System.out.println("选择操作:\n1、新增\n2、删除\n3、前序遍历\n4、中序遍历\n5、后序遍历\n\n0、退出");
            oper = sc.nextInt();
            switch (oper){
                case 1:{
                    System.out.println("输入添加的数字:");
                    int input = sc.nextInt();
                    rbtree.put(input);
                    System.out.println("添加成功");
                };break;
                case 2:{
                    System.out.println("输入删除的数字:");
                    int input = sc.nextInt();
                    rbtree.remove(input);
                    System.out.println("删除成功");
                };break;
                case 3:rbtree.DLR();break;
                case 4:rbtree.LDR();break;
                case 5:rbtree.LRD();break;
                case 0:System.exit(0);break;
                default:continue;
            }
        }
        
    }
    
    /**
     * 红黑树性质(满足平衡二叉树的前提下):
     * 1、所有节点要么为黑色,要么为红色
     * 2、根节点为黑色
     * 3、所有叶子节点为黑色(null视为叶子节点)
     * 4、红色节点的子节点为黑色
     * 5、对每个节点,从其到达叶子的所有路径中黑色节点个数相同
     * _ 
     * 向红黑树中插入一个节点后可能会出现的情况(其中新节点记为红色,先将新节点插入到叶节点位置,此时可能破坏红黑树性质,执行fixRBTree函数)
     * (插入过程默认原树已经满足红黑树性质,部分地方未做异常校验,如果树不满足红黑树性质,可能会出异常)
     * fixRBTree(z)
     * _ 情况1:z为根节点:将z.color设置为black,满足红黑树性质,结束
     * _ 情况2:z的父节点为黑色,满足红黑树性质,结束
     * _ 情况3:z的父节点为红色,叔节点为红色,祖父节点为黑色:设置父、叔节点为黑色、祖父节点为红色,再令z指向祖父节点,递归fixRBTree(z),然后返回
     * _ 
     * _ 情况4:z的父节点为红色,叔节点为黑色,祖父节点为黑色
     * _    情况4.1 z的父节点为祖父节点的左孩子
     * _        情况4.1.1 z为父节点的右孩子:z绕z的父节点左旋(z的父节点变成z的左子节点),令z指向z的左子节点=》情况4.1.2
     * _        情况4.1.2 z为父节点的左孩子:将z的父节点、祖父节点变色,使z的父节点绕z的祖父节点右旋(此时,父节点为黑色,满足情况2,结束)
     * _ 
     * _    情况4.2 z的父节点为祖父节点的右孩子
     * _        情况4.2.1 z为父节点的左孩子:z绕z的父节点右旋(z的父节点变成z的右子节点),令z指向z的右子节点=》情况4.2.2
     * _        情况4.2.2 z为父节点的右孩子:将z的父节点、祖父节点变色,使z的父节点绕z的祖父节点左旋(此时,父节点为黑色,满足情况2,结束)
     *
     * _ 
     * 分析:情况1、2、4.x均为结束情况。只有情况3递归调用函数,而且递归的过程中z向上移动两级,因此z向上的复杂度为 O(lgn)
     * 分析:有旋转转的地方只有情况4.x,且无论哪次到情况4.x,最多旋转两次就结束
     * 分析:因此,插入节点复杂度为:将z插入叶子节点的复杂度O(lgn) + 递归复杂度 O(lgn) + 旋转复杂度O(1)  =  O(lgn)
     */
    /**
     * INSERT
     ***/
    public void put(int val) {
        
        Node ins = new Node(val);
        
        Node par = null, np = null, z = ins;
        if (root == null) {
            root = ins;
        } else {
            np = root;
            while (np != null) {
                par = np;
                if (np.val > ins.val) {
                    np = np.left;
                } else {
                    np = np.right;
                }
            }
            ins.parent = par;
            if (par.val > ins.val) {
                par.left = ins;
            } else {
                par.right = ins;
            }
        }
        RB_INSERT_FIXUP(z);
    }
    
    private void RB_INSERT_FIXUP(Node z) {
        
        // case1  z is root of tree
        if (z == root) {
            setBLACK(z);
            return;
        }
        // case2  z.parent is black
        if (isBLACK(z.parent)) return;
        // case3  z.uncle and z.parent is red and z.grandfather is black
        if (isRED(uncleOf(z)) && isRED(z.parent) && isBLACK(z.parent.parent)) {
            setBLACK(uncleOf(z));
            setBLACK(z.parent);
            setRED(z.parent.parent);
            RB_INSERT_FIXUP(z.parent.parent);
            return;
        }
        // case4 z.uncle is black and z.parent is red and z.grandfather is black(the third is always true beacuse of z.uncle's color)
        // case 4.1 z.parent is left of z.grandfather
        if (z.parent.parent.left == z.parent) {
            // case 4.1.1 z is right of z.parent
            if (z.parent.right == z) {
                RotateLeft(z);
                z = z.left;// be case 4.1.2
            }
            // case 4.1.2 z is left of z.parent
            setBLACK(z.parent);
            setRED(z.parent.parent);
            RotateRight(z.parent);
        } else {// case 4.2 z.parent is right of z.grandfather
            // case 4.2.1 z is left of z.parent
            if (z.parent.left == z) {
                RotateRight(z);
                z = z.right;    // be case 4.2.2
            }
            // case 4.2.2 z is right of parent
            setBLACK(z.parent);
            setRED(z.parent.parent);
            RotateLeft(z.parent);
        }
    }
    /**     END INSERT  ***/
    /**
     * REMOVE
     ***/
    
    public boolean remove(int val) {
        
        Node p = root;
        while (p != null) {
            if (val == p.val) break;
            else if (val < p.val) p = p.left;
            else p = p.right;
        }
        if (p == null) return false;
        RB_DELETE(p);
        return true;
    }
    
    /**
     * 结论1:若z 有且仅有一个非空子节点,那么z 必为黑色,且子节点为红色,且子节点只有一层
     * <p>
     * 情况1 :z.left  z.right 均不为空,此时找到 z 的后继节点,记为zNext(必无左子节点),将zNext与z替换,此时删除z即可(此时z无左节点,转入情况3、4)
     * 情况2 :z.left 不为空      (根据结论1,z为黑色,且z.left  为红色,且z.left  无子节点)此时直接用z.left  替换掉z,并将z.left  染黑
     * 情况3 :z.right 不为空     (根据结论1,z为黑色,且z.right 为红色,且z.right 无子节点)此时直接用z.right 替换掉z,并将z.right 染黑
     * 情况4 :z.left z.right均为空  fixup
     */
    private void RB_DELETE(Node z) {
        
        Node zNext = null;
        if (z.left != null && z.right != null) {    // 经过处理之后,z 不含左子节点(右子节点存在性不确定)
            // 找到z 的后继,并将z的后继放至z处(此时删除z后继位置节点即可,而且此时,z的后继必无左子节点)
            zNext = TREE_MINIMUM(z.right);
            z.val = zNext.val;
            z = zNext;
        }
        
        Node replacement = (z.left == null) ? z.right : z.left;
        if (replacement != null) {// 情况2、3
            replacement.parent = z.parent;
            if (z.parent == null)
                root = replacement;
            else if (z == z.parent.left)
                z.parent.left = replacement;
            else
                z.parent.right = replacement;
            // z为删除的点,将其从树种摘除
            z.left = z.right = z.parent = null;
            
            // 修正错误
            if (isBLACK(z))
                RB_DELETE_FIXUP(replacement);
        } else if (z.parent == null) { 
            root = null;
        } else { //  情况4
            if (z.color == BLACK)
                RB_DELETE_FIXUP(z);
            // 摘除节点z
            if (z.parent != null) {
                if (z == z.parent.left)
                    z.parent.left = null;
                else if (z == z.parent.right)
                    z.parent.right = null;
                z.parent = null;
            }
        }
        
    }
    
    /**
     * 修复红黑树:
     * 
     * 情况1 :x 为 x.parent 左子节点
     * _    情况1.1 :x 兄弟节点为红色(此时父节点必为黑,x兄弟节点的两子节点为黑):兄弟节点置黑,父节点置红,兄弟节点绕父节点左旋(x兄弟节点的左节点变为x新的兄弟节点)。此时转为情况1.2
     * _    情况1.2 :x 兄弟节点为黑色 
     * _        情况1.2.1 :x 的兄弟节点左右孩子均为黑色:将x兄弟节点置红,x指向x 的父节点
     * _        情况1.2.2 :x 的兄弟节点仅右孩子节点为黑色:将x兄弟节点置红,x兄弟节点左孩子置黑,将x.brother.left 绕 x.brother右旋。(转入情况1.2.3)
     * _        情况1.2.3 :x 的兄弟节点仅左孩子节点为黑色:x兄弟节点置红,x父节点置黑,将x 节点,将x.brother 绕 x.parent 左旋(新x = root结束)
     * _
     * 情况2 :x 为x.parent 右子节点(情况同上,左右相反)
     * _
     * _
     */
    private void RB_DELETE_FIXUP(Node x) {
        while (x != root && isBLACK(x)) {
            if (x == x.parent.left) {
                Node sib = x.parent.right;
                
                if (isRED(sib)) {
                    setBLACK(sib);
                    setRED(x.parent);
                    RotateLeft(sib);
                    sib = x.parent.right;
                }
                
                if (isBLACK(sib.left) &&
                        isBLACK(sib.right)) {
                    setRED(sib);
                    x = x.parent;
                } else {
                    if (isBLACK(sib.right)) {
                        setBLACK(sib.left);
                        setRED(sib);
                        RotateRight(sib.left);
                        sib = x.parent.right;
                    }
                    sib.color = x.parent.color;
                    setBLACK(x.parent);
                    setBLACK(sib.right);
                    RotateLeft(x.parent.right);
                    x = root;
                }
            } else { // symmetric
                Node sib = x.parent.left;
                
                if (isRED(sib)) {
                    setBLACK(sib);
                    setRED(x.parent);
                    RotateRight(sib);
                    sib = x.parent.left;
                }
                
                if (isBLACK(sib.right) &&
                        isBLACK(sib.left)) {
                    setRED(sib);
                    x = x.parent;
                } else {
                    if (isBLACK(sib.left)) {
                        setBLACK(sib.right);
                        setRED(sib);
                        RotateLeft(sib.right);
                        sib = x.parent.left;
                    }
                    sib.color = x.parent.color;
                    setBLACK(x.parent);
                    setBLACK(sib.left);
                    RotateRight(sib);
                    x = root;
                }
            }
        }
        setBLACK(x);
    }
    
    /**
     * 命名变量n 为当前节点,
     * 情况1:节点n 兄弟节点红色(根据红黑树性质,x.parent 为黑色,左(右)旋,兄弟节点及父节点变色)=》情况2
     * 情况2:节点n 兄弟节点w 为黑色,父节点红色(父节点染黑,兄弟节点染红)=》结束后  删除 x 节点
     * 情况3:节点n 兄弟节点w 为黑色,父节点黑色
     */
//    private void RB_DELETE_FIXUP(Node x) {
//        //while()
//    }
    private Node TREE_MINIMUM(Node z) {
        while (z.left != null) {
            z = z.left;
        }
        return z;
    }
    /**     END REMOVE  ***/
    
    
    /*** R2L     T
     *           |
     *          Gra
     *         /   \
     *        A    P
     *       / \  / \
     *      x  x l  r
     *
     *      此处旋转默认p的父节点一定存在(内部调用,旋转的时候已经确定Gra节点存在了)
     * ***/
    private void RotateLeft(Node p) {
        if (p == null || p.parent.left == p) return;
        Node l = p.left;
        Node T = p.parent.parent;
        setRight(p.parent, l);   // 将p左节点设置为gra右节点 ①
        setParent(l, p.parent);  // 将p左节点设置为gra右节点 ②
        setLeft(p, p.parent);    // 将p的父节点设置为p的左节点 ①
        setParent(p.parent, p);  // 将p的父节点设置为p的左节点 ②
        setParent(p, T);
        if (T == null) {        // 如果T为空,说明 p.parent为根节点,将p 赋值给root,并将root 的parent置空
            root = p;
            //root.parent=null;
        } else if (T.left == p.left) {
            T.left = p;
        } else {
            T.right = p;
        }
    }
    
    /**
     * L2R
     *
     * @param p
     */
    private void RotateRight(Node p) {
        if (p == null || p.parent.right == p) return;
        Node r = p.right;
        Node T = p.parent.parent;
        setLeft(p.parent, r);       // 将p右节点设置为gra左节点 ①
        setParent(r, p.parent);     // 将p右节点设置为gra左节点 ②
        setRight(p, p.parent);      // 将p的父节点设置为p的右节点 ①
        setParent(p.parent, p);     // 将p的父节点设置为p的右节点 ②
        setParent(p, T);
        if (T == null) {        // 如果T为空,说明 p.parent为根节点,将p 赋值给root,并将root 的parent置空
            root = p;
            //p.parent = null;
        } else if (T.left == p.right) {
            T.left = p;
        } else {
            T.right = p;
        }
    }
    
    
    private static final class Node {
        protected Node left = null;
        protected Node right = null;
        protected Node parent = null;
        
        protected int val;
        
        protected boolean color = RED;
        
        Node(int k) {
            this.val = k;
        }
    }
    
    private void setLeft(Node par, Node ch) {
        if (par == null) return;
        par.left = ch;
    }
    
    private void setRight(Node par, Node ch) {
        if (par == null) return;
        par.right = ch;
    }
    
    private void setParent(Node ch, Node par) {
        if (ch == null) return;
        ch.parent = par;
    }
    
    private Node uncleOf(Node p) {
        if (p.parent.parent.left == p.parent) return p.parent.parent.right;
        return p.parent.parent.left;
    }
    
    private boolean isRED(Node p) {
        if (p == null) return false;
        return p.color == RED;
    }
    
    private boolean isBLACK(Node p) {
        return !isRED(p);
    }
    
    private void setBLACK(Node p) {
        if (p == null) return;
        p.color = BLACK;
    }
    
    private void setRED(Node p) {
        p.color = RED;
    }
    
    private boolean isRight(Node p) {
        if (p.parent.right == p) return true;
        return false;
    }
    
    private boolean isLeft(Node p) {
        return !isRight(p);
    }
    
    private Node brotherOf(Node p) {
        if (isLeft(p)) return p.parent.right;
        return p.parent.left;
    }
    
    private Node getNode(int k) {
        
        Node p = root;
        while (p != null) {
            if (k < p.val) p = p.left;
            else if (k > p.val) p = p.right;
            else return p;
        }
        return null;
    }
    
    
    private static boolean RED = false;
    private static boolean BLACK = true;
    
    /**
     * 先序遍历
     */
    public void DLR() {
        
        System.out.println("FIRST_ORDER");
        System.out.print("\t");
        DLR0(root);
        System.out.println();
    }
    
    private void DLR0(Node p) {
        if (p == null) return;
        System.out.print("[ " + p.val + (isBLACK(p) ? "_BLACK" : "_RED") + " ]" + " => ");
        DLR0(p.left);
        DLR0(p.right);
    }
    /**
     * 中序遍历
     */
    public void LDR() {
        
        System.out.println("MID_ORDER");
        System.out.print("\t");
        LDR0(root);
        System.out.println();
    }
    
    private void LDR0(Node p) {
        if (p == null) return;
        LDR0(p.left);
        System.out.print("[ " + p.val + (isBLACK(p) ? "_BLACK" : "_RED") + " ]" + " => ");
        LDR0(p.right);
    }
    /**
     * 后序遍历
     */
    public void LRD() {
        
        System.out.println("LAST_ORDER");
        System.out.print("\t");
        LRD0(root);
        System.out.println();
    }
    
    private void LRD0(Node p) {
        if (p == null) return;
        LRD0(p.left);
        LRD0(p.right);
        System.out.print("[ " + p.val + (isBLACK(p) ? "_BLACK" : "_RED") + " ]" + " => ");
    }
    
}


 
 
 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值