红黑树结构

1. 简述

红黑树是一种二叉搜索树,具有以下特点:

  1. 每个节点具有颜色属性,黑色或者红色
  2. 根节点是黑色的
  3. 每个叶节点(NIL)是黑色的
  4. 红色节点的子节点都是黑色的
  5. 任意节点到其所有叶子节点的路径上黑色节点数相同
  6. n个节点的红黑树高度至多2lg(n+1),相关操作时间复杂度O(lgn)

注:java中treeSet、treeMap是通过红黑树结构实现的

2. 旋转

/*左旋
    将右孩子y旋转到当前节点x,当前节点x及其左子树作为y的左子树
    将y的左子树移为x的右子树
     */
    public void leftRotate(Node x){
        Node y = x.right;
        if(y!=nil){
            //y的左子树移为x的右子树
            x.right = y.left;
            if(y.left!=nil)
                y.left.father = x;
            //y顶替x的位置
            y.father = x.father;
            if(x.father==nil)
                root = y;
            else if(x==x.father.left)
                x.father.left = y;
            else
                x.father.right = y;
            //x作为y的左子树
            y.left = x;
            x.father = y;
        }
    }
    /*右旋
    将左孩子y旋转到当前节点x,当前节点x及其右子树作为y的右子树
    将y的右子树移为x的左子树
     */
    public void rightRotate(Node x){
        Node y = x.left;
        if(y!=nil){
            //y的右子树移为x的左子树
            x.left = y.right;
            if(y.right!=nil)
                y.right.father = x;
            //y顶替x的位置
            y.father = x.father;
            if(x.father==nil)
                root = y;
            else if(x.father.left == x)
                x.father.left = y;
            else 
                x.father.right = y;
            //x作为y的右子树
            y.right = x;
            x.father = y;
        }
    }

3. 插入

public void add(int value){
        Node newNode = new Node(value);//创建新节点

        Node y = nil;
        Node x = root;
        while(x!=nil){ //递归查找插入位置
            y=x;
            if(newNode.value < x.value)
                x=x.left;
            else
                x=x.right;
        }
        newNode.father = y;
        if(y==nil) { //第一个节点,更新根节点
            root = newNode;
        }
        else if(newNode.value < y.value) //判断新增节点作为左孩子还是右孩子
            y.left = newNode;
        else
            y.right = newNode;
        newNode.left = nil;
        newNode.right = nil;
        newNode.color = 'R'; //默认红色
        rbInsertFixup(newNode); //更新颜色
    }

3.1 修复规则

插入元素后破坏红黑树规则,需要调整红黑树,如下情况

/*规则修复
    1.当新增节点的父节点是黑色,则无需调整
    2.新增节点为根节点,则改为黑色
    3.父节点为红色
      a.叔节点为红色,叔、父都调为黑色,爷爷调为红色
      b.叔节点为黑色,当前节点为右孩子,和父节点进行左旋
      c.叔节点为黑色,当前节点为左孩子,父节点调为黑色,爷节点调为红色,右旋
     */
    private void rbInsertFixup(Node node){
        while(node.father.color == 'R'){
            Node y = null;
            //获取叔节点
            if(node.father==node.father.father.left)
                y = node.father.father.right;
            else
                y = node.father.father.left;
            if(y!=null) {
                if (y.color == 'R') {
                    node.father.color = 'B';
                    y.color = 'B';
                    node.father.father.color = 'R';
                    node = node.father.father; //取爷爷节点向上迭代
                } else if (node == node.father.right) {
                    node = node.father;
                    leftRotate(node);
                } else {
                    node.father.color = 'B';
                    node.father.father.color = 'R';
                    rightRotate(node);
                }
            }
        }
        root.color = 'B';
    }

4. 删除

    /*节点上移
      移除节点u,节点v上移
     */
    private void transplant(Node u, Node v){
        if(u.father == nil)
            root = v;
        else if(u==u.father.left)
            u.father.left = v;
        else
            u.father.right = v;
        if(v!=nil)
            v.father = u.father;
    }
    public void delete(Node z){
        Node x;
        Node y = z;
        char originalColor = y.color;
        if(z.left==nil) {  //无左孩子(包含无孩子),右孩子上移
            x=z.right;
            transplant(z, z.right);
        }
        else if(z.right==nil) {  //无右孩子
            x=z.left;
            transplant(z, z.left); //左孩子上移
        }
        else{//有两个孩子
            //取右孩子树的最小值,最小值没有左孩子,将最小节点提到原先z的位置
            y = minimum(z.right);
            originalColor = y.color;  //最小节点上提,其右子树可能破坏规则
            x=y.right;
            if(y.father!=z){
                transplant(y,y.right);// 最小节点提取出后右孩子树上移
                y.right = z.right; //y成为右子树中第一个节点,且没有左孩子
                y.right.father = y;
            }else {
                x.father = y;
            }
            transplant(z,y);  //移除z,y上移
            y.left = z.left;  //原z的左孩子,变为y的左孩子
            y.left.father = y;
            y.color=z.color;  //最小节点颜色与删除节点保持一致,此处未破坏规则
        }
        if(originalColor=='B')  //只有原节点是黑色才破坏规则
            rbDeleteFixup(x);
    }

4.1 修复规则 

    private void rbDeleteFixup(Node x){
        while(x!=root && x.color == 'B'){
            Node w = null;
            //获取兄弟节点
            if(x==x.father.left)
                w = x.father.right;
            else
                w = x.father.left;
            if(w!=null) {
                //兄弟节点是红色
                if (w.color == 'R') {
                    w.color = 'B';
                    x.father.color = 'R';
                    if(w == x.father.right) {
                        leftRotate(x.father);
                        w = x.father.right;
                    }else {
                        rightRotate(x.father);
                        w = x.father.left;
                    }
                } else { //兄弟节点为黑色
                    //兄弟节点的两个子节点都是黑色
                    if (w.left.color == 'B' && w.right.color == 'B') {
                        w.color = 'R';
                        x = x.father;
                    } else {
                        //兄弟节点左孩子红色,右孩子黑色
                        if (w.right.color == 'B') {
                            w.left.color = 'B';
                            w.color = 'R';
                            rightRotate(w);
                            w = x.father.right;
                        }else {
                           //兄弟节点的右孩子是红色
                            w.color = x.father.color;
                            x.father.color = 'B';
                            w.right.color = 'B';
                            if(w == x.father.right)
                              leftRotate(x.father);
                            else
                                rightRotate(x.father);
                            x = root;
                        }
                    }
                }
            }
        }
        x.color = 'B';
    }

5. 其他

 红黑树的扩张:设f是n 个结点的红黑树T扩张的属性,且假设对任一结点,f的值仅依赖于结点x、x.left和x.right 的信息,还可能包括x.left.f和x..right.f。那么,我们可以在插入和删除操作期间对 T的所有结点的f值进行维护,并且不影响这两个操作的O(lgn)渐近时间性能。

6. 完整代码

package s22;

public class RedBlackTree {
    //节点类,包含颜色、父节点、左孩子、右孩子、值
    class Node{
        char color;//R:red,B:black
        Node father =null;
        Node left = null;
        Node right = null;
        int value;
        private Node(){}
        private Node(int value){this.value = value;}
    }
    private Node root;
    private int size;
    private Node nil; //叶子节点
    public RedBlackTree(){
        size = 0;
        nil = new Node();
        nil.color = 'B';
        root = nil;
    }
    public void add(int value){
        Node newNode = new Node(value);//创建新节点

        Node y = nil;
        Node x = root;
        while(x!=nil){ //递归查找插入位置
            y=x;
            if(newNode.value < x.value)
                x=x.left;
            else
                x=x.right;
        }
        newNode.father = y;
        if(y==nil) { //第一个节点,更新根节点
            root = newNode;
        }
        else if(newNode.value < y.value) //判断新增节点作为左孩子还是右孩子
            y.left = newNode;
        else
            y.right = newNode;
        newNode.left = nil;
        newNode.right = nil;
        newNode.color = 'R'; //默认红色
        rbInsertFixup(newNode); //更新颜色
    }
    /*规则修复
    1.当新增节点的父节点是黑色,则无需调整
    2.新增节点为根节点,则改为黑色
    3.父节点为红色
      a.叔节点为红色,叔、父都调为黑色,爷爷调为红色
      b.叔节点为黑色,当前节点为右孩子,和父节点进行左旋
      c.叔节点为黑色,当前节点为左孩子,父节点调为黑色,爷节点调为红色,右旋
     */
    private void rbInsertFixup(Node node){
        while(node.father.color == 'R'){
            Node y = null;
            //获取叔节点
            if(node.father==node.father.father.left)
                y = node.father.father.right;
            else
                y = node.father.father.left;
            if(y!=null) {
                if (y.color == 'R') {
                    node.father.color = 'B';
                    y.color = 'B';
                    node.father.father.color = 'R';
                    node = node.father.father; //取爷爷节点向上迭代
                } else if (node == node.father.right) {
                    node = node.father;
                    leftRotate(node);
                } else {
                    node.father.color = 'B';
                    node.father.father.color = 'R';
                    rightRotate(node);
                }
            }
        }
        root.color = 'B';
    }
    /*左旋
    将右孩子y旋转到当前节点x,当前节点x及其左子树作为y的左子树
    将y的左子树移为x的右子树
     */
    public void leftRotate(Node x){
        Node y = x.right;
        if(y!=nil){
            //y的左子树移为x的右子树
            x.right = y.left;
            if(y.left!=nil)
                y.left.father = x;
            //y顶替x的位置
            y.father = x.father;
            if(x.father==nil)
                root = y;
            else if(x==x.father.left)
                x.father.left = y;
            else
                x.father.right = y;
            //x作为y的左子树
            y.left = x;
            x.father = y;
        }
    }
    /*右旋
    将左孩子y旋转到当前节点x,当前节点x及其右子树作为y的右子树
    将y的右子树移为x的左子树
     */
    public void rightRotate(Node x){
        Node y = x.left;
        if(y!=nil){
            //y的右子树移为x的左子树
            x.left = y.right;
            if(y.right!=nil)
                y.right.father = x;
            //y顶替x的位置
            y.father = x.father;
            if(x.father==nil)
                root = y;
            else if(x.father.left == x)
                x.father.left = y;
            else
                x.father.right = y;
            //x作为y的右子树
            y.right = x;
            x.father = y;
        }
    }
    /*节点上移
      移除节点u,节点v上移
     */
    private void transplant(Node u, Node v){
        if(u.father == nil)
            root = v;
        else if(u==u.father.left)
            u.father.left = v;
        else
            u.father.right = v;
        if(v!=nil)
            v.father = u.father;
    }
    public void delete(Node z){
        Node x;
        Node y = z;
        char originalColor = y.color;
        if(z.left==nil) {  //无左孩子(包含无孩子),右孩子上移
            x=z.right;
            transplant(z, z.right);
        }
        else if(z.right==nil) {  //无有孩子
            x=z.left;
            transplant(z, z.left); //左孩子上移
        }
        else{//有两个孩子
            //取右孩子树的最小值,最小值没有左孩子,将最小节点提到原先z的位置
            y = minimum(z.right);
            originalColor = y.color;  //最小节点上提,其右子树可能破坏规则
            x=y.right;
            if(y.father!=z){
                transplant(y,y.right);// 最小节点提取出后右孩子树上移
                y.right = z.right; //y成为右子树中第一个节点,且没有左孩子
                y.right.father = y;
            }else {
                x.father = y;
            }
            transplant(z,y);  //移除z,y上移
            y.left = z.left;  //原z的左孩子,变为y的左孩子
            y.left.father = y;
            y.color=z.color;  //最小节点颜色与删除节点保持一致,此次未破坏规则
        }
        if(originalColor=='B')  //只有原节点是黑色才破坏规则
            rbDeleteFixup(x);
    }
    private void rbDeleteFixup(Node x){
        while(x!=root && x.color == 'B'){
            Node w = null;
            //获取兄弟节点
            if(x==x.father.left)
                w = x.father.right;
            else
                w = x.father.left;
            if(w!=null) {
                if (w.color == 'R') {
                    w.color = 'B';
                    x.father.color = 'R';
                    if(w == x.father.right) {
                        leftRotate(x.father);
                        w = x.father.right;
                    }else {
                        rightRotate(x.father);
                        w = x.father.left;
                    }
                } else {
                    if (w.left.color == 'B' && w.right.color == 'B') {
                        w.color = 'R';
                        x = x.father;
                    } else {
                        if (w.right.color == 'B') {
                            w.left.color = 'B';
                            w.color = 'R';
                            rightRotate(w);
                            w = x.father.right;
                        }else {
                            w.color = x.father.color;
                            x.father.color = 'B';
                            w.right.color = 'B';
                            if(w == x.father.right)
                              leftRotate(x.father);
                            else
                                rightRotate(x.father);
                            x = root;
                        }
                    }
                }
            }
        }
        x.color = 'B';
    }
    //根据key迭代查找节点
    public Node iterativeTreeSearch(Node x, Integer key){
        while(x!=null && key != x.value){
            if(key < x.value)
                x = x.left;
            else
                x = x.right;
        }
        return x;
    }
    //获取最小节点
    public Node minimum(Node x){
        while(x.left != null)
            x = x.left;
        return x;
    }
    //获取树的最大节点
    public Node maximum(Node x){
        while(x.right != null)
            x = x.right;
        return x;
    }
    //获取根节点
    public Node getRoot() {
        return root;
    }
    //获取大小
    public Integer getSize() {
        return size;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值